我的iOS应用中有一个ViewController流(Flow A
)。流程A相当复杂(视情况而定,某些视图控制器显示得很早,或者根本没有显示,等等)。为了处理这个问题,我正在使用协调器模式。
代码(简体):
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()
方法呈现视图控制器的逻辑。到目前为止一切顺利。
现在我有第二个流程Flow B
,与流程A大部分不同。除了我想在两者之间共享视图控制器之外,我们将其称为SharedViewController
。事情变得奇怪了,因为我对如何在两者之间共享这个视图控制器没有真正的好主意。
问题:我有两种通信方式-协调器将自己设置为它所提供的视图控制器的协调器,视图控制器在协调器上调用方法以响应用户交互。 SharedViewController
由两个协调员之一管理,无论如何,它都必须以某种方式将信息传递给当前的协调员。
到目前为止,我发现了两个解决方案,它们都不令人满意:
仅处理SharedViewController
的附加协调器-这是很多开销,并且在很大程度上违反了协调器的目的。
在FlowACoordinatable
中实现FlowBCoordinatable
,SharedViewController
,...,并且具有多个协调器属性,并在适当的时间调用所有这些属性。还有很多开销,样板代码和对协调器的调用。
关于如何很好地解决此问题的任何想法?
答案 0 :(得分:0)
我遇到了同样的情况,我也不知道最好的解决方案是什么。我有一个必须在不同的协调器中使用的viewController。
当给定的viewController本身不需要协调器时,可以。例如,我们称其为DisplayPopupViewController。 我创建了一个名为CanDisplayPopupProtocol的协议:
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协议,所以代替此:
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
}
我确信这不是协议的最佳用法,希望遵循此线程的人将对此问题有更好的解决方案。