我最近开始使用协调器(例如: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 。父协调器AuthCoordinatorLoginCoordinator数组/集中删除其子childControllers

顺便说一句,为什么您需要将子协调器保留在数组中,然后考虑如何删除它们。我尝试了另一种方法, View 模型保留了子协调器,一旦解除分配了 View 模型,协调器也会重新分配。为我工作。

但是我个人不喜欢这么多的连接,并且不考虑使用单个协调器对象进行所有操作的更简单方法。

关于ios - MVVM协调器并弹出UIViewController,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44110768/

10-10 21:12