CoordinatorLibrary
示例
要运行示例项目,请克隆仓库,然后首先从示例目录中运行pod install
安装
CoordinatorLibrary可通过CocoaPods获得。要安装它,只需将以下行添加到您的Podfile中
pod 'CoordinatorLibrary'
Coordinator
Coordinator如其名所示,即协调器。它们旨在将导航逻辑从视图控制器抽象出来,帮助更好地分离关注点。总体而言,Coordinator包括三个协议,用于明确定义每个类型遵守它们的职责,并允许进行某些协议组合。
可协调的
该协议有一个要求 start()
。这是您应该设置 Coordinator ViewController 的方法。
导航可协调的
该协议只有一个要求。符合该协议的类型应有一个 ,它可以是任何
UINavigationController
的子类。它还有一些扩展来抽象出在您的应用中呈现另一个屏幕的实现细节。
public func navigate(to viewController: UIViewController, with presentationStyle: PresentationStyle, animated: Bool)
子可协调的
该协议有四个要求。
var children: [String: Coordinatable] { get set }
func add(child coordinator: Coordinatable, key: String)
func remove(coordinator: Coordinatable)
func removeAllChidren()
注意: 它们已被实现为协议扩展,因此您在采用协议时无需这样做。
关于采用协调器协议的注意: 虽然您有权在自己的情况下使用这些协议并根据您的意愿进行组合,但我会建议您检查方便类,这些类抽象了一些您可能想要使用协调器协议的方式。继续阅读下面以查看信息。
应用协调器
open class AppCoordinator: Coordinatable, ChildCoordinatable
应用协调器是一个基类,负责启动应用导航。它通常位于 AppDelegate
中,根据一些自定义逻辑启动对其子项的协调。
注意: AppCoordinator
需要被继承。这是因为基于您的应用或业务需求,您可能需要以不同的方式处理对子项的协调。它也是一个方便类,旨在抽象出处理设置应用程序窗口的过程。这使您能够专注于真正重要的事情,即配置您的应用程序导航逻辑。
例如,以下是子类化和自定义导航的示例。在现实世界的用例中,这可能会基于当前用户是否已登录。
class CoordinatorExampleAppCoordinator: AppCoordinator {
override func start() {
Bool.random() ? startChildA() : startChildB()
}
}
导航协调器
open class NavigationCoordinator<T: UIViewController>: NavigationFlowCoordinator
导航协调器是一个用于处理导航堆栈中从视图控制器导航到和从视图控制器返回的专用通用基类。
子协调器
open class ChildCoordinator<T: UIViewController>: NavigationCoordinator<T>, ChildCoordinatable
子协调器是一个用于处理从其父协调器添加/移除子协调器的专用通用基类。子协调器继承自 NavigationFlowCoordinator
。
当我们派生 ChildCoordinator
时,我们就可以处理如图所示添加和从父协调器移除子协调器。
child = ViewControllerBCoordinator(presenter: presenter)
add(child: child)
child.start()
child.movingFromParent { [weak self] in self?.removeChild() }
func removeChild() {
remove(child: child)
}
注意:在点击导航控制器上的返回按钮时,您需要调用 movingFromParent
来接收通知。在这种情况下,您可以做出任何您想要的操作。例如,如上面所示,在闭包中调用 remove(child:)
将子协调器从其父级的子层次结构中移除,从而释放内存。
注意:有三种方法可以通知子协调器正从父协调器中被移除,即您可以派生一个称为 CoordinatorViewController
的专用视图控制器来处理 movingFromParent
通知分发,或者您可以在自己的视图控制器中实现此内容,如果您不想接受免费功能的话
private unowned let coordinator: RemoveAction
public init(coordinator: RemoveAction) {
self.coordinator = coordinator
super.init(nibName: nil, bundle: nil)
}
open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if isMovingFromParent {
coordinator.movingFromParent?()
}
}
默认情况下,任何继承自 NavigationFlowCoordinator
的类已经实现了 RemoveAction
协议要求,您只需使用初始化器传入 self
作为参数,或者您也可以进行属性注入。
通信
协调器之间的通信是一个 1:1 父亲 -> 子的关系。有两种方法可以处理这种通信,即委托和闭包。我个人更喜欢使用闭包来处理通信,因为它们通常更容易引入,并且能减少父 -> 子之间的紧密耦合。
在这个例子中,ViewControllerACoordinator 持有 ViewControllerA 的引用,每次点击 ViewControllerA 中的按钮时都会调用一个闭包。didTapButton: (() -> Void)?
对于接收到此事件的响应,协调器将启动 ViewControllerBCoordinator 并调用 start()
来进行到 ViewControllerB 的转换。
class ViewControllerACoordinator: ChildCoordinator<ViewControllerA> {
override func start() {
viewController = ViewControllerA()
navigate(to: viewController, with: .push, animated: true)
viewController.didTapButton = { [startViewCoordinatorB] in
startViewCoordinatorB()
}
}
private func startViewCoordinatorB() {
let child = ViewControllerBCoordinator(presenter: presenter)
add(child: child)
child.start()
}
}
StoryboardSupportable
public protocol StoryBoardSupportable: class
StoryboardSupportable 是一个协议,它允许基于故事板实例化支持视图控制器。当使用故事板时,这就是您实例化视图控制器的方式 -
// when using storyboards
viewController = ViewControllerA.instantiate(from: "Main")
注意:如果您使用视图模型/展示者等,您需要在实例化视图控制器之后使用属性初始化。
当您想要一个视图控制器能够像上面那样实例化自身时,您使其符合 StoryBoardSupportable。
class ViewControllerA: UIViewController, StoryBoardSupportable
作者
kaunamohammed, [email protected]
许可
CoordinatorLibrary 适用于 MIT 许可证。更多信息请查看 LICENSE 文件。
CoordinatorLibrary
接下来去哪里
查看此存储库的 changeFeed,了解版本间的变更情况
协调器可能一开始难以理解,但当你迈过起步的那一步后,它竟然是如此简单且可扩展的架构。网上一些建议您阅读的优秀文章,可以加深您对协调器工作原理的理解。
此外,还有一个来自 NSSpain 的精彩视频 [https://vimeo.com/144116310],在那里推动协调器发展的Soroush Khanlou介绍了他在应用程序中使用协调器的方法。
贡献
有问题?请发起 issue!有想法?请发起 pull request!
如果您喜欢这个库,请
干杯