gpt4 book ai didi

swift - 如何正确实现导航器模式

转载 作者:搜寻专家 更新时间:2023-10-31 21:46:10 25 4
gpt4 key购买 nike

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

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

下面是 Sundell 说明的 Navigator 模式的思想

导航器

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()
}
}
}

View Controller

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)
}
}

现在在 AppDelegate 中我想做类似的事情

let factory = LoginViewControllerFactory()
let loginViewController = factory.makeLoginViewController()
let rootNavigationController = UINavigationController(rootViewController: loginViewController)
window?.rootViewController = rootNavigationController

但我必须以某种方式将 rootNavigationController 传递到 factory 中,以便正确构造 loginViewController 对吗?因为它需要导航器,导航器需要导航 Controller 。如何做到这一点?

最佳答案

我最近也在尝试实现 Sundell 的 Navigator 模式并遇到了同样的循环依赖。我不得不向初始 Navigator 添加一些额外的行为来处理这个奇怪的 Bootstrap 问题。我相信您应用中的后续 Navigators 可以完美地遵循博客的建议。

这是使用 JGuo(OP)示例的新初始 Navigator 代码:

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

private var navigationController: UINavigationController?
// This ^ doesn't need to be weak, as we will instantiate it here.

private let viewControllerFactory: LoginViewControllerFactory

// New:
private let appWindow: UIWindow?
private var isBootstrapped = false
// We will use this ^ to know whether or not to set the root VC

init(appWindow: UIWindow?, // Pass in your app's UIWindow from the AppDelegate
viewControllerFactory: LoginViewControllerFactory) {
self.appWindow = appWindow
self.viewControllerFactory = viewControllerFactory
}

func navigate(to destination: Destination) {
let viewController = makeViewController(for: destination)

// We'll either call bootstrap or push depending on
// if this is the first time we've launched the app, indicated by isBootstrapped
if self.isBootstrapped {
self.pushViewController(viewController)
} else {
bootstrap(rootViewController: viewController)
self.isBootstrapped = true
}
}

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

// Add these two new helper functions below:
private func bootstrap(rootViewController: UIViewController) {
self.navigationController = UINavigationController(rootViewController: rootViewController)
self.appWindow?.rootViewController = self.navigationController
}

private func pushViewController(_ viewController: UIViewController) {
// Setup navigation look & feel appropriate to your app design...
navigationController?.setNavigationBarHidden(true, animated: false)
self.navigationController?.pushViewController(viewController, animated: true)
}
}

现在在 AppDelegate 中:

class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

window = UIWindow(frame: UIScreen.main.bounds)
let factory = LoginViewControllerFactory()
let loginViewController = factory.makeLoginViewController()
loginViewController.navigate(to: .signup) // <- Ideally we wouldn't need to signup on app launch always, but this is the basic idea.
window?.makeKeyAndVisible()

return true
}
...
}

关于swift - 如何正确实现导航器模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51228633/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com