如何正确实现导航器模式

JGu*_*Guo 7 factory dependency-injection circular-dependency swift

我正在关注 John Sundell 的帖子以实现导航器模式(https://www.swiftbysundell.com/posts/navigation-in-swift)。基本思想是,与 Coordinator 模式相比,每个视图控制器可以简单地调用,navigator.navigate(to: .someScreen)而不必知道其他视图控制器。

我的问题是,因为为了构造一个视图控制器我需要一个导航器,为了构造一个导航器我需要一个导航控制器,但我想让视图控制器成为导航控制器的根,解决这个问题的最佳方法是什么以一种尊重依赖注入最佳实践的方式循环依赖?

下面是 Sundell 说明的导航器模式的想法

航海家

protocol Navigator {
    associatedtype Destination    
    func navigate(to destination: Destination)
}

class LoginNavigator: Navigator {
    enum Destination {
        case loginCompleted(user: User)
        case signup
    }

    private weak var navigationController: UINavigationController?
    private let viewControllerFactory: LoginViewControllerFactory

    init(navigationController: UINavigationController,
         viewControllerFactory: LoginViewControllerFactory) {
        self.navigationController = navigationController
        self.viewControllerFactory = viewControllerFactory
    }

    func navigate(to destination: Destination) {
        let viewController = makeViewController(for: destination)
        navigationController?.pushViewController(viewController, animated: true)
    }

    private func makeViewController(for destination: Destination) -> UIViewController {
        switch destination {
        case .loginCompleted(let user):
            return viewControllerFactory.makeWelcomeViewController(forUser: user)
        case .signup:
            return viewControllerFactory.makeSignUpViewController()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图控制器

class LoginViewController: UIViewController {
    private let navigator: LoginNavigator

    init(navigator: LoginNavigator) {
        self.navigator = navigator
        super.init(nibName: nil, bundle: nil)
    }

    private func handleLoginButtonTap() {
        navigator.navigate(to: .loginCompleted(user: user))
    }

    private func handleSignUpButtonTap() {
        navigator.navigate(to: .signup)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在AppDelegate我想做一些类似的事情

let factory = LoginViewControllerFactory()
let loginViewController = factory.makeLoginViewController()
let rootNavigationController = UINavigationController(rootViewController: loginViewController)
window?.rootViewController = rootNavigationController
Run Code Online (Sandbox Code Playgroud)

但是我必须以某种方式将 the 传递给rootNavigationControllerthefactory以便loginViewController正确构造它,对吗?因为它需要一个导航器,它需要导航控制器。怎么做?

ami*_*rfl 1

这能解决问题吗?在应用程序委托中:

let factory = LoginViewControllerFactory()
let navController = UINavigationController()

let loginNavigator = LoginNavigator(navigationController: navController, viewControllerFactory: factory)

loginNavigator.navigate(to: .signup) // The example doesn't have a .login Destination, but it can easily be added to the factory, so using .signup instead

window?.rootViewController = navController
Run Code Online (Sandbox Code Playgroud)