知识点
- 给tableview添加command绑定支持的分类方法
- [RACSignal merge:]操作
- RACTuple使用,快速包装数据,快速提取数据,容错能力强可存放nil
界面如下
- 上拉加载更多 下拉刷新
- 点击按钮选择 底部view根据选择情况作出响应
- 案例代码https://git.coding.net/codingheew/RACComand.git
https://github.com/heeween/RACComand.git
RACComand与TableView刷新事件绑定
- 写UITableView支持RACComand事件绑定的分类
// UITableView+RACCommandSupport.m 文件中代码
- (void)setRac_Refreshcommand:(RACCommand *)command {
objc_setAssociatedObject(self, UITableViewRACRefreshCommandKey, command, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (command == nil) return;
__weak typeof(self) weakSelf = self;
self.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
__strong typeof(self) self = weakSelf;
[command execute:self];
}];
}
这里的分类主要就是给Tableview增加MJRefresh,并且将传入command参数传入MJRefresh执行的block中
- viewmodel中定义刷新和加载更多的事件
//CCOrderViewModel.m 文件中代码
NSArray *array = @[
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"瑞立东方花城",@"billPrice":@241.00},
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"杭州滨江区星光大道",@"billPrice":@21.00},
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"杭杭州萧山国际机场",@"billPrice":@10.00},
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"红石中央大厦",@"billPrice":@19.24},
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"杭州半山国家森林公园",@"billPrice":@2.00},
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"瑞立东方花城",@"billPrice":@15.00},
@{@"time":@"今天 17:00",@"startAddress":@"浙江吉利控股集团有限公司",@"endAddress":@"瑞立东方花城",@"billPrice":@241.00},];
NSMutableArray *modelArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[modelArray addObject:[CCOrderModel orderWith:obj]];
}];
@weakify(self);
self.refreashCmd = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
@strongify(self);
[self.orderArray removeAllObjects];
[self.orderArray addObjectsFromArray:modelArray];
[subscriber sendNext:self.orderArray];
[subscriber sendCompleted];
return nil;
}];
}];
self.loadMoreCmd = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
@strongify(self);
[self.orderArray addObjectsFromArray:modelArray];
[subscriber sendNext:self.orderArray];
[subscriber sendCompleted];
return nil;
}];
}];
这里定义两个command,将数据包在signal中,再包在command中
- 控制器中将viewmode的command事件和UItableview绑定
控制器中的绑定就非常简单,这样绑定之后,tableview的刷新事件就会进入viewmodel的command的block中
// ViewController.m 文件中代码 command绑定
self.tableView.rac_Refreshcommand = self.viewModel.refreashCmd;
self.tableView.rac_Dropcommand = self.viewModel.loadMoreCmd;
- 给viewmodel添加两个刷新事件组合之后的,tableview刷新signal
目的是在控制器,只需要监听viewmodel的一个signal,可以统一刷新tableview
//CCOrderViewModel.m 文件中代码
RACSignal *refreshEndSignal = [[self.refreashCmd executionSignals] switchToLatest];
RACSignal *loadmoreEndSignal = [[self.loadMoreCmd executionSignals] switchToLatest];
// 上拉和下拉两个信号统一输出
self.reloadTableViewSignal = [RACSignal merge:@[refreshEndSignal, loadmoreEndSignal]];
- 控制器绑定Signal的代码
这里是利用rac_liftSelector将viewmodel刷新signal直接和控制器的reloadTableView:绑定
// ViewController.m 文件中代码
[self rac_liftSelector:@selector(reloadTableView:) withSignals:self.viewModel.reloadTableViewSignal, nil];
/** 刷新列表 */
- (void)reloadTableView:(id)obj {
[self.tableView.mj_header endRefreshing];
[self.tableView.mj_footer endRefreshing];
[self.tableView reloadData];
NSString *numberString = self.viewModel.selectedOrders.first;
NSString *priceString = self.viewModel.selectedOrders.second;
BOOL enable = [self.viewModel.selectedOrders.third boolValue];
self.bottomView.totalPriceLabel.text = priceString;
self.bottomView.totalTravelLabel.text = numberString;
[self.bottomView subviewEnable:enable];
}
- 其他cell赋值就很简单了
在这里我说下我对cell创建的理解,我认为cell不应该持有model.cell赋值就通过暴露出来的UI控件在控制器中赋值就好了.这样cell是一个很纯净的cell.没有任何逻辑.内聚性很强.逻辑方面的bug也绝对不需要去cell中找.
MVVM的架构模式,就是极大的提高viewmodel层逻辑代码的内聚性,使得UI代码和业务代码完全隔离,维护的时候很专心的去对应的文件找问题就可以了.通过事件绑定在控制器中.极大的简化控制器,控制器只存在业务代码的调度,非常方便找到对应的业务代码.