2

I'm using SwiftUI 1.0 in all my views starting from MainView which is the Home screen other than the Login as I'm using a client LoginSDK which is made via UIKit.

So in LoginViewController, I'm able to push the MainView() on sucessful login with code below:

func showMainView() {
    let host = UIHostingController(rootView: MainView())
    self.navigationController?.navigationBar.isHidden = true
    self.navigationController?.pushViewController(host, animated: true)
}

In the MainView, I have tried implementing a logout method that sets the LoginViewController as the rootView when the user clicks the logout Button with the code below:

struct MainView: View {
    
    var body: some View {
            NavigationView {
                    VStack {
                        Button(action: {
                           logout()
                        }, label: {
                            Image("Logout")
                                .resizable()
                                .frame(width: 20, height: 16)
                        })
                    }
            }
    }

  //Method to logout and set the RootNavigationViewController as rootViewController
  func logout () {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    //The LoginViewController is embedded in RootNavigationViewController
    let rootViewController = storyboard.instantiateViewController(withIdentifier: "RootNavigationViewController") as! UINavigationController
            
    if let window = UIApplication.shared.windows.first {
        window.rootViewController = rootViewController
        window.endEditing(true)
        window.makeKeyAndVisible()
    }
  }

}

The above logout method implementation is doing nothing. I would like to know how can I navigate back to LoginViewController (A UIKit UIViewController) from MainView (A SwiftUI struct).

  • try presenting rather than pushing the view. Another thing is you can use binding to show/hide views. – Rj19 Feb 23 '21 at 06:57
  • @Rj19, thank you for your answer, bu the business requirement is to push the MainView from LoginViewController. Also, for showing and hiding views, have you tried it already using both UIKit's UIViewController and SwiftUI's view? If yes, can you reference some codes. Thanks! – Josh Byanec McFergan Feb 23 '21 at 10:44
  • what I use for showing and hiding is Binding as its really easy and expressive. However your case may be a bit different. Still here is the Link : https://swiftwithmajid.com/2020/04/08/binding-in-swiftui/ – Rj19 Feb 23 '21 at 12:11

2 Answers2

1

Possible solution is to use callback like

struct MainView: View {
    var didLogout: () -> ()
    
    // ... other code

  func logout () {
    // ... make logout activity here and on completion perform

    // DispatchQueue.main.async {  << if logout callback in different queue
       didLogout()
    // }
  }
}

and now we can use it as

func showMainView() {
    let host = UIHostingController(rootView: MainView() { [weak self] in
       self?.navigationController?.popViewController(animated: true)  // << here !!
    })

    self.navigationController?.navigationBar.isHidden = true
    self.navigationController?.pushViewController(host, animated: true)
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Hi Asperi, thank you for your answer. I tried this implementation and it's partially working in a sense that it pops to LoginViewController when the callback is triggered. But when the user is already logged-in, the rootViewController would be the MainView hence the callback for popping to LoginViewController is not working anymore. Do you know another implementation of directly setting a rootview on a certain function call from SwiftUI that will navigate back to UIKit's LoginViewController? Thanks in advance! – Josh Byanec McFergan Feb 23 '21 at 10:49
0

This worked perfectly for me, I hope this helps!

let storyboard = UIStoryboard(name: "Main", bundle: nil)

let rootViewController = storyboard.instantiateViewController(withIdentifier: "YourIdentifier")

           if let window = UIApplication.shared.windows.first {
               window.rootViewController = rootViewController
               window.endEditing(true)
               window.makeKeyAndVisible()
           }