Navigation Coordinator in SwiftUI
Asked Answered
V

0

9

Historically using UIKit we have always used the Coordinator Pattern to handle Navigation.

Starting a new app in SwiftUI however it is not clear how to handle this.

For example, our currently flow would be:

  1. App Launches
  2. App Coordinator Starts
  3. Loads "Start Scene"
  4. Start scene checks auth state and calls delegate on App Coordinator
  5. App Coordinator starts showHomeScene or showAuthScene

Something like

final class AppCoordinator: BaseCoordinator {

  private(set) var navigationController: UINavigationController?

  init(navigationController: UINavigationController?) {
    self.navigationController = navigationController
  }

  override func start() {
    showStartScene()
  }

  private func showStartScene() {
    let configurator = StartConfigurator()
    let viewController = configurator.create(self)
    navigationController?.setViewControllers([viewController], animated: false)
  }

  private func showHomeScene() {
    let coordinator = HomeCoordinator(self, navigationController: navigationController)
    store(coordinator: coordinator)
    coordinator.start()
  }

  private func showAuthScene() {
    let coordinator = AuthCoordinator(self, navigationController: navigationController)
    store(coordinator: coordinator)
    coordinator.start()
  }

}

extension AppCoordinator: StartSceneDelegate {
  func userNeedsToAuthenticate() {
    showAuthScene()
  }

  func userIsAuthenticated() {
    showHomeScene()
  }
}

However as we are not using UIViewController how does navigationController?.setViewControllers([viewController], animated: false) work?

Should we still just set using a UIHostingController?

Something like - navigationController?.setViewControllers([UIHostingController(rootView: StartView())], animated: false)

It seems a bit weird as I don't believe the SwiftUI views will really make use a UINavigationController as they use NavigationView and NavigationLink.

Unless the UINavigationController really just serves as a wrapper?

I was considering using@EnvironmentObject within the coordinator and based on the auth state replacing the root view controller in the coordinator also.

Venus answered 24/3, 2020 at 7:57 Comment(6)
You'd start from here Data Flow Through SwiftUIMaltese
I have seen this video, it talks about moving data between views within the app. I am interested in a navigation pattern, moving between views, not moving data between views.Venus
SwiftUI has reactive nature, so even moving between views is managed by reacting on changes in some data, most appropriate native pattern is MVVM, so... back to data flow.Maltese
hmmm so if I want to push from view A to view B, then view A must set up all the dependencies for view B? This seems very backwards for a "UI" framework. I'll rewatch the video incase I'm missing something.Venus
No, it means that there should be somewhere enum States { case A: case B } and some view model holding that state, and root view which depending of the state in view model shows either ViewA or ViewB, and coordinator can manage switching those states in shared view model, which in case of SwiftUI can be EnvironmentObject set to root.Maltese
@Maltese I asked a similar question here: #61188631 Do you have maybe some example projects to see your approach in action?Overheat

© 2022 - 2024 — McMap. All rights reserved.