简介
RxController 是一个基于 RxFlow 和 RxSwift 的 MVVM-C 开发库。如果您不熟悉它们,请首先学习这些框架。
- RxSwift (https://github.com/ReactiveX/RxSwift)
- RxCocoa (https://github.com/ReactiveX/RxSwift)
- RxFlow (https://github.com/RxSwiftCommunity/RxFlow)
RxController 提供以下基本视图控制器和视图模型类:
- RxViewController
- RxViewModel
这些类使得在流、父视图模型和子视图模型之间传输数据变得容易。
示例应用
以下基于 RxController 的 2 个开源应用用于更好地理解此库。
- Githuber,一个简单的 Github 搜索应用:https://github.com/MuShare/Githuber
- Httper,一个 RESTful api 测试应用:https://github.com/MuShare/Httper-iOS
建议指南
我们建议遵循此指南开发基于 RxController、RxFlow 和 RxSwift 的 MMVM-C。如果您不熟悉这些框架,建议首先阅读RxController、RxFlow 和 RxSwift 的文档。
- 第 1 章:[介绍](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter1-introduction.md)
- 第 2 章:[使用 RxFlow](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter2-rxflow.md)
- 第 3 章:[视图控制器](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter3-viewcontroller.md)
- 第 4 章:[视图模型](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter4-viewmodel.md)
- 第 5 章:[视图](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter5-view.md)
- 第 6 章:[表格和集合视图单元格](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter6-cell.md)
- 第 7 章:[管理类](https://github.com/RxSwiftCommunity/RxController/blob/master/document/chapter7-manager.md)
文档
RxController 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中
pod 'RxController'
示例
示例应用程序有助于您理解如何使用 RxController。要运行示例项目,请先克隆该存储库,然后从 Example 目录运行 pod install
。
视图控制器泛型类
RxController 提供了泛型类 RxViewController
。它避免了在视图控制器类中使用 Optional
或 Implicit Unwrapping Option
类型来对视图模型属性进行操作。
在演示应用中,我们通过扩展 RxViewModel 类定义视图模型类,然后通过扩展 RxViewController 泛型类定义视图控制器类。
// View model class
class InfoViewModel: RxViewModel {
}
// View controller class
class InfoViewController: RxViewController<InfoViewModel> {
}
然后,我们可以以安全的方式初始化 InfoViewController,如下所示。
func navigate(to step: Step) -> FlowContributors {
guard let appStep = step as? AppStep else {
return .none
}
switch appStep {
case .start:
let infoViewController = InfoViewController(viewModel: InfoViewModel())
navigationController.pushViewController(infoViewController, animated: false)
return .viewController(infoViewController)
}
}
RxViewController 内部提供了以下标准方法来构建 UI 和绑定数据。
open func subviews() -> [UIView]
子视图方法返回一个视图数组。这些视图将被有顺序地添加到视图控制器的根视图中。
open func createConstraints()
为根视图的子视图创建约束。
open func bind() -> [Disposable]
绑定方法返回一个 Disposable
数组。可以在该方法中列出 RxSwift 风格的数据绑定,而无需写入 disposed(by:)
方法。
直接从视图模型访问生命周期
可以直接从视图模型访问以下生命周期信号。
viewDidLoad: Observable
viewWillAppear: Observable
viewDidAppear: Observable
viewWillDisappear: Observable
viewDidDisappear: Observable
视图布局完成:Observable
视图将要布局子视图:Observable
视图安全区域偏移量变化:Observable
在父视图模型和子视图模型之间交换数据
在RxFlow的典型MVVM-C架构中,视图模型通过使用流类和steps.accept()
方法来交换数据。使用RxChildViewModel
,我们可以在父视图模型和子视图模型之间交换数据,而无需使用流类。
使用以下方法将子视图控制器添加到根视图或其父控制器自定义视图。
/**
Add a child view controller to the root view of the parent view controller.
@param childController: a child view controller.
*/
override open func addChild(_ childController: UIViewController)
/**
Add a child view controller to the a container view of the parent view controller.
The edges of the child view controller is same as the container view by default.
@param childController: a child view controller.
@param containerView: a container view of childController.
*/
open func addChild(_ childController: UIViewController, to containerView: UIView)
为了在视图模型之间传输数据,我们在父视图模型中定义一些事件。
struct InfoEvent {
static let name = RxControllerEvent.identifier()
static let number = RxControllerEvent.identifier()
}
如图所示,事件只能在父视图模型及其第一代子视图模型之间传递。例如,我们上面定义的InfoEvent
,在InfoViewModel
、NameViewModel
和NumberViewModel
之间可以使用。
从父视图模型(InfoViewModel
)发送一个事件。
events.accept(InfoEvent.name.event("Alice"))
从子视图模型(NameViewModel
和NumberViewModel
)发送一个事件。
parentEvents.accept(event: InfoEvent.name.event("Alice"))
在父视图模型(InfoViewModel
)中接收一个事件。
var name: Observable<String?> {
return events.value(of: InfoEvent.name)
}
在子视图模型(NameViewModel
和NumberViewModel
)中接收一个事件。
var name: Observable<String?> {
return parentEvents.value(of: InfoEvent.name)
}
请注意,在视图模型的init
方法中订阅RxControllerEvent
是无效的。必须在使用prepareForParentEvents
方法时订阅或绑定RxControllerEvent
。
override func prepareForParentEvents() {
// Subscribe an event.
parentEvents.unwrappedValue(of: ParentEvent.sample, type: EventData.self).subscribe(onNext: {
// ...
}.disposed(by: disposeBag))
// Bind an event or a parent event to a relay directly.
bindParentEvents(to: data, with: ParentEvent.sample)
// Bind an observable type to an event or a parent event directly.
bindToEvent(from: data, with: Event.sample)
}
视图模型中的事件路由器
在上面的图中,如果需要将事件从InfoViewModel
转发到FirstNameViewModel
,应将中间视图模型NameViewModel
用作路由器来转发数据。为了简化路由视图模型中的数据转发,提供了在RxViewModel
中的forward
方法。
// Forward a parent event to an event
func forward(parentEvent: ,toEvent:)
// Forward a parent event to an event with a `flatMapLatest` closure
func forward(parentEvent: ,toEvent: ,flatMapLatest:)
// Forward an event to a parent event
func forward(toEvent: ,parentEvent:)
// Forward an event to a parent event with a `flatMapLatest` closure
func forward(toEvent: , parentEvent: ,flatMapLatest:)
从子视图模型向流程发送步骤
通常情况下,无法从子视图模型撤销RxFlow中steps.accept()
方法,因为我们没有在流的navigate(to)
方法中返回子视图控制器和子视图模型的实例。
使用RxController,可以直接从子视图模型向流程发送步骤。
steps.accept(DemoStep.stepname)
RxTree
RxController提供了一个命令行工具rxtree
,它可以打印流程和控制器之间的关系,就像使用tree
命令一样。
➜ ./rxtree MainFlow
MainFlow
├── ProjectFlow
│ ├── RequestFlow
│ │ ├── AddProjectViewController
│ │ ├── RequestViewController
│ │ ├── ResultViewController
│ │ ├── SaveToProjectViewController
│ ├── ProjectIntroductionViewController
│ ├── ProjectNameViewController
│ ├── ProjectViewController
│ ├── ProjectsViewController
├── RequestFlow
│ ├── AddProjectViewController
│ ├── RequestViewController
│ ├── ResultViewController
│ ├── SaveToProjectViewController
├── SettingsFlow
│ ├── IPAddressViewController
│ ├── PingViewController
│ ├── SettingsViewController
│ ├── WhoisViewController
├── AddProjectViewController
使用CocoaPods安装RxTree
rxtree
依赖于RxController的设计。一旦RxController更新,旧的rxtree
版本可能就不再有效。因此,建议使用CocoaPods的post_install
来安装。
post_install do |installer|
system("bash #{Pathname(installer.sandbox.root)}/RxController/rxtree/build_for_xcode.sh")
end
一旦执行了pod install
或pod update
,就会同时安装相应的rxtree
版本。
使用RxTree
执行后的文件rxtree
将被复制到项目的根目录。必须选择一个强节点作为树的根节点,这个节点可以是Flow
的子类或RxViewController
的子类。
./rxtree MainFlow
为了防止递归调用,rxtree
的默认最大级别是10。这意味着默认情况下只能列出10级流程和控制器。要更改最大级别,请使用maxLevels
参数。
./rxtree MainFlow --maxLevels 5
作者
lm2343635, [email protected]
许可
RxController在MIT许可下可用。有关更多信息,请参阅LICENSE文件。