我最近开始使用协调器(例如:MVVM with Coordinators and RxSwift)来改进当前的MVVM体系结构。这是从UIViewController中删除与导航相关的代码的不错的解决方案。
但是我在1种特定情况下遇到了麻烦。当默认的后退按钮或边缘滑动手势弹出UIViewController时,就会出现此问题。
使用列表详细信息界面的快速示例:
列表UIViewController由UINavigationController内部的ListCoordinator显示。轻按一个项目时,ListCoordinator将创建一个DetailCoordinator,将其注册为子协调器并启动它。 DetailCoordinator将详细信息UIViewController推送到UINavigationController上,就像每条MVVM-C博客文章所说明的那样。
每个MVVM-C博客文章都无法说明的是,当默认的后退按钮或边缘滑动手势弹出详细信息UIViewController时会发生什么。
DetailCoordinator应该负责弹出详细信息UIViewController,但是a)它不知道点击了后退按钮,并且b)自动弹出。另外,ListCoordinator无法从其子协调器中删除DetailCoordinator。
一种解决方案是使用自定义后退按钮,该按钮会向点击发出信号,并将其传递给DetailCoordinator。另一个可能正在使用UINavigationControllerDelegate。
别人如何解决这个问题?我确定我不是第一个。
最佳答案
我将Action用于协调器之间以及协调器和 View Controller 之间的通信。
AuthCoordinator
final class AuthCoordinator: Coordinator {
func startLogin(viewModel: LoginViewModel) {
let loginCoordinator = LoginCoordinator(navigationController: navigationController)
loginCoordinator.start(viewModel: viewModel)
viewModel.coordinator = loginCoordinator
// This is where a child coordinator removed
loginCoordinator.stopAction = CocoaAction { [unowned self] _ in
if let index = self.childCoordinators.index(where: { type(of: $0) == LoginCoordinator.self }) {
self.childCoordinators.remove(at: index)
}
return .empty()
}
}
}
登录协调员
final class LoginCoordinator: Coordinator {
var stopAction: CocoaAction?
func start(viewModel: LoginViewModel) {
let loginViewController = UIStoryboard.auth.instantiate(LoginViewController.self)
loginViewController.setViewModel(viewModel: viewModel)
navigationController?.pushViewController(loginViewController, animated: true)
loginViewController.popAction = CocoaAction { [unowned self] _ in
self.stopAction?.execute(Void())
return .empty()
}
}
}
LoginViewController
class LoginViewController: UIViewController {
var popAction: CocoaAction?
override func didMove(toParentViewController parent: UIViewController?) {
super.didMove(toParentViewController: parent)
if parent == nil { // parent is `nil` when the vc is popped
popAction?.execute(Void())
}
}
}
因此,
LoginViewController
在弹出时执行该 Action 。协调员LoginCoordinator
知道该 View 已弹出。它从其父协调器AuthCoordinator
触发另一个 Action 。父协调器AuthCoordinator
从LoginCoordinator
数组/集中删除其子childControllers
。顺便说一句,为什么您需要将子协调器保留在数组中,然后考虑如何删除它们。我尝试了另一种方法, View 模型保留了子协调器,一旦解除分配了 View 模型,协调器也会重新分配。为我工作。
但是我个人不喜欢这么多的连接,并且不考虑使用单个协调器对象进行所有操作的更简单方法。
关于ios - MVVM协调器并弹出UIViewController,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44110768/