NavigationFlowCoordinator
协调器是指在应用中组织屏幕流程的帮助设计模式。Krzysztof Zabłocki在这篇博客文章中进行了很好的解释。
NavigationFlowCoordinator
是这种模式的基本实现,并提供了一些额外有用的功能。
(跳转到
安装)CocoaPods
pod 'NavigationFlowCoordinator'
(跳转到
协调器)Coordinator
协议是表示可以开始和完成某些流的对象的抽象。通常由协调器控制的流部分包括几个 UIViewControllers
。`Coordinator` 协议非常简单
public protocol Coordinator: class {
func start()
func finish()
}
流程协调器
FlowCoordinator
是 Coordinator
的基本实现,旨在被特定的协调器实现类继承。 FlowCoordinator
引入了通过子父关系链式连接协调器的功能。任何 FlowCoordinator
都可以通过调用此方法来启动子协调器。
func start(childCoordinator: FlowCoordinator)
它还提供了发送和处理 FlowEvents
的能力。该机制在本文件的后续部分将详细介绍。
导航流程协调器
NavigationFlowCoordinator
是一项流程协调器实现,有助于根据 UINavigationController
控制流程。设计为子类,而不是直接使用。一个非常基础的实现示例可能如下所示
class MoviesListCoordinator: NavigationFlowCoordinator {
override func createMainViewController() -> UIViewController? {
let viewController = MoviesListViewController()
viewController.flowDelegate = self
return viewController
}
}
extension MoviesListCoordinator: MovieListFlowDelegate {
func addNewMovie() {
// starts child coordinator that handles other part of flow
start(childCoordinator: MovieCreateOrUpdateCoordinator(movieId: nil))
}
func showAbout() {
// present view controller being part of flow controlled by this coordinator
push(viewController: AboutViewController())
}
}
重写 createMainViewController()
方法至关重要,因为这个定义的视图控制器成为协调器的“主要视图控制器”。这意味着一旦主视图控制器从导航控制器中弹出,协调器就结束了其流程。通过直接将新视图控制器推送到导航视图中,或者使用其中一种封装在导航视图控制器上的操作函数(如在 showAbout()
方法中)来展示新视图控制器。当我们想要切换到由其他协调器控制的流程的部分时,我们需要按照 addNewMovie()
方法启动子协调器。通过子父关系链式连接的协调器共享导航控制器实例,除非其中任何一个节点重写了 navigationController
属性。当协调器启动子协调器时,无需存储对其的引用,因为内部机制会为我们保留这个引用。当子协调器结束(无论是通过从导航控制器中弹出主视图控制器,还是调用 finish()
方法)时,引用将释放。
FlowEvent
通常使用委托或块从子协调器传递数据到其父协调器。有时可能会有一系列协协调器,我们可能希望将一些数据从最后一个子协调器传递到几级以上的 Coordinate 中。如果我们使用委托来做这件事,就不可避免地要涉及到内部协调器(位于感兴趣传递数据的协调器之间的协调器)及其委托,即使它们对此类事件毫无兴趣。我们最后得在每个委托中添加新方法,编写代码在来自子协调器的回调上触发这些方法,等等。使用 FlowEvents
,这个问题的一个更简单的解决方案。 FlowEvents
机制添加了发送实现 FlowEvent
协议的事件对象的能力。示例
send(flowEvent: MovieUpdatedFlowEvent(movieId: movieId))
事件可以通过重写方法由链中的任何父协协调器处理
override func handle(flowEvent: FlowEvent) -> Bool {
if let movieUpdatedFlowEvent = flowEvent as? MovieUpdatedFlowEvent, movieUpdatedFlowEvent.movieId == movieId {
movieDetailsViewController.invalidateMovieData()
}
return false
}
协调器
处理事件可以防止事件进一步发送。从handle(flowEvent:)
函数返回true会导致事件不再向上传递。通过返回false,我们仍然可以处理事件,为父级协调器处理事件留出机会。
示例
在NavigationFlowCoordinatorExample文件夹中,您可以找到使用NavigationFlowCoordinators
的示例应用程序。