学习函数式编程已经有一个半月了,学习了RxSwift和RAC2.X,尝试过写一些小的demo,但是一直没有了解过MVVM中是如何使用RAC进行通信的,由于公司项目准备使用MVVM+RAC模式重构,在github找到了使用MVVM+RAC构建的Github开源app:GitBucket,本文主要记录该项目中RAC在MVVM模式中的应用。
项目类图
项目中主要有两大继承体系:MRCViewModel和MRCViewController,分别对应ViewModel层和Controller层,实现代码复用
在MRCViewModel父类中存放了一些需发送给Controller层的信号,如标题变化,错误信号,控制器隐藏信号等;
MRCViewController中实现了监听ViewModel信号的方法,如监听ViewModel的标题变化
1 | RAC(self.navigationItem, titleView) = [RACObserve(self.viewModel, titleViewType).distinctUntilChanged map:^(NSNumber *value) { |
另外项目中使用了Service层提供ViewModel所需的各种服务
OCTClient:Github的三方库api,提供了RAC的支持
MRCRepositoryService/MRCRepositoryServiceImpl:应用自有的服务类
MRCViewModelServices:提供界面跳转的实现
界面跳转
作者没有使用系统提供的push/present操作实现界面跳转,而是在MRCViewModelServices中实现了一系列空操作
1 | - (void)pushViewModel:(MRCViewModel *)viewModel animated:(BOOL)animated {} |
之后在视图层维护了一个MRCNavigationControllerStack,通过RAC订阅Service的跳转方法的调用,提供真正的界面跳转的代码实现
1 | @weakify(self) |
这样Controller只需要做数据绑定即可,需要跳转界面时,ViewModel层调用service的方法,MRCNavigationControllerStack监听到方法调用后做界面跳转[self.services pushViewModel:viewModel animated:YES];
另外由于VM层不可引入View层的类,所以跳转的一系列方法的传参都为ViewModel,通过维护一个ViewModel与Controller层的映射字典,实现了视图与界面的分离@property (nonatomic, copy) NSDictionary *viewModelViewMappings; // viewModel到view的映射
#RAC用法
###通过RAC提供代理的函数实现
使用rac_signalForSelector:fromProtocol
方法订阅键盘的回车键
1 | @weakify(self) |
###RAC监听UI事件
使用rac_signalForControlEvents
方法订阅按钮的点击信号,当按钮被点击时,执行登录的命令
1 | [[self.loginButton |
###RAC监听通知
使用rac_addObserverForName
方法订阅app从后台进入前台的通知,takeUntil保证在对象销毁后取消订阅
1 | [[[[NSNotificationCenter defaultCenter] |
###RAC在TableView中的应用
监听ViewModel中dataSource数组的变化,dataSource发生改变时重新加载tableView
1 | @weakify(self) |
刷新列表时显示loading菊花,刷新完成时隐藏
1 | [[[RACSignal |
使用rac_sequence和map将model转化为viewmodel数据源
1 | - (NSArray *)dataSourceWithEvents:(NSArray *)events { |