ios - 在 Coordinator 模式中重用 View Controller

标签 ios swift design-patterns coordinator-pattern

我的 iOS 应用程序中有一个 ViewController 的流程 (Flow A)。流程 A 相当复杂(根据情况,一些 View Controller 会提前显示,或者根本不显示等)。为了处理这个问题,我正在使用协调器模式。

代码(简化):

protocol Coordinator {
    func start()
}

protocol FlowACoordinatable {
    var coordinator: FlowACoordinator
}

class FlowACoordinator: Coordinator {

    private var navigationController: UINavigationController

    private var firstVC: FirstViewController
    private var secondVC: SecondViewController

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

    func start() { ... }

    func present(_ viewController: (FlowACoordinatable & UIViewController)) {
        viewController.coordinator = self
        self.navigationController.pushViewController(viewController, animated: true)
    }

    ...
}

class FirstViewController: UIViewController, FlowACoordinatable {

    var coordinator: FlowACoordinator?

    func buttonTapped() {
        self.coordinator?.goToNextStep()
    }
}

....

FlowACoordinator 包含有关如何以及何时使用 present() 方法呈现 View Controller 的逻辑。到目前为止一切顺利。

现在我有了第二个流,Flow B,它与 Flow A 有很大不同。除了我想在两者之间共享一个 View Controller ,我们称它为 SharedViewController。这就是事情变得奇怪的地方,因为我不知道如何在两者之间共享这个 View Controller 。

问题:我有两种通信方式——协调器将自己设置为它所呈现的 View Controller 的协调器,并且 View Controller 调用协调器上的方法作为对用户交互的响应。 SharedViewController 由两个协调器之一管理,但是,它必须以某种方式将信息传递给当前的协调器,无论它是哪个。

到目前为止,我找到了两个解决方案,但都不令人满意:

  1. 仅处理 SharedViewController 的附加协调器 - 这会产生大量开销,并且在很大程度上违背了协调器的目的。

  2. SharedViewController 中实现 FlowACoordinatableFlowBCoordinatable ...,并具有多个协调器属性并在适当的时候调用所有这些属性次。还有很多开销、样板代码和对协调器的调用。

关于如何很好地解决这个问题有什么想法吗?

最佳答案

我遇到了同样的情况,但我也不确定处理它的最佳方案是什么。我有一个必须在不同协调器中使用的 viewController。

当给定的 viewController 本身不需要协调器时是可以的。例如,我们称它为 DisplayPopupViewController。 我创建了一个名为 CanDisplayPopupProtocol 的协议(protocol):

protocol CanDisplayPopupProtocol {}

extension CanDisplayPopupProtocol where Self: Coordinator {
    func toDisplayPopupViewController() {
        let vc = DisplayPopupViewController.instantiate()
        navigationController.pushViewController(vc, animated: true)
    }
}

然后在 Coordidnator1 中:

extension Coordinator1: CanDisplayPopupProtocol{}

在 Coordinator2 中:

extension Coordinator2: CanDisplayPopupProtocol{}

现在两个协调器都有 toDisplayPopupViewController() 方法。

正如我之前所说,当我不需要将协调器传递给 viewController 时这很好,在这种情况下 DisplayPopupViewController 不需要协调器,因为它将被关闭并且不需要任何导航。

但是在这种情况下,当需要为 viewController 分配一个协调器时,它会变得更加复杂,我传递的是哪个协调器?

我发现在我看来不是很优雅的解决方案是将 viewController 中的协调器类型更改为 Coordinator 协议(protocol),因此不是这样:

weak var coordinator: Coordinator1?

我将使用:

weak var coordinator: Coordinator?

然后在 CanDisplayPopupProtocol 中,我将测试正在处理的协调器并将正确的协调器分配给 viewController,如下所示:

protocol CanDisplayPopupProtocol {}

extension CanDisplayPopupProtocol where Self: Coordinator {
    func toDisplayPopupViewController() {
        let vc = DisplayPopupViewController().instantiate()
        switch self {
        case is Coordinator1:
            vc.coordinator = self as? Coordinator1
        case is Coordinator2:
            vc.coordinator = self as? Coordinator2
        default: break
        }
        navigationController.pushViewController(vc, animated: true)
    }
}

这并不漂亮,还有另一个缺点。在 DisplayPopupViewController 中,每次我需要使用一种协调器方法时,我都需要测试我使用的是哪种协调器类型。

switch coordinator {
case is Coordinator1:
    (coordinator as! Coordinator1).toDisplayPopupViewController()
case is Coordinator2:
    (coordinator as! Coordinator2).toDisplayPopupViewController()
default: break
}

我确信这不是协议(protocol)的最佳使用方式,希望关注此主题的人能够针对此问题提供更好的解决方案。

关于ios - 在 Coordinator 模式中重用 View Controller,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52169238/

相关文章:

javascript - JavaScript 中的 UI 模式

java - 构造函数过度注入(inject)和门面服务概念

multithreading - 什么是常见的并发陷阱?

ios - SLComposeViewController 在 ios7 中将图像发布到 facebook 上

ios - 当按钮移动时移动 uiview

ios - 如何获取 objective-c 中包含毫秒的时间戳的int值

cocoa - 如何更改 Nib 上 NSSplitView 分隔线的颜色?

ios - 如何使用键值将数组与字典分组。

ios - 在 Swift 中避免类型名称冲突

swift - 名称节点始终为零 - ARKit Swift