为何要用MVVM?只是由于它不会让我时常懵逼。javascript
每次作完项目事后,都会被本身庞大的ViewController代码吓坏,无论是什么网络请求、networking data process、跳转交互逻辑通通往ViewController里面塞,就算是本身写的代码,也不敢直视。我不得不思考是否是MVC模式太过落后了,毕竟它叫作Massive View Controller,其实说MVC落后不太合理,说它太原生了比较合适。java
MVC模式的历史很是的久远,它其实不过是对编程模式的一种模块化,无论是MVVM、MVCS、仍是听起来就不寒而栗的VIPER,都是对MVC标准的三个模块的继续划分,细分下去,使每一个模块的功能更加的独立和单一,而最终目的都是为了提高代码的规范程度,解耦,和下降维护成本。具体用什么模式须要根据项目的需求来决定,而这里,我简单的说说本身对MVVM架构的理解和设计思想,浅谈拙见。程序员
传统的MVC模式分为:Model、View、Controller。Model是数据模型,有胖瘦之分,View负责界面展现,而Controller就负责剩下的逻辑和业务,瞬间Controller心中一万个草泥马奔腾而过。编程
MVVM模式只是多了一个ViewModel,它的做用是为Controller减负,将Controller里面的逻辑(主要是弱业务逻辑)转移到自身,其实它涉及到的工做不止是这些,还包括页面展现数据的处理等。(后序章节会有具体讲解)数组
个人设计是这样的:网络
RAC是一个强大的工具,它和MVVM模式的结合使用只能用一个词形容————完美。架构
固然,有些开发者不太愿意用这些东西,大概是由于他们以为这破坏了代理、通知、监听、block等的复杂逻辑观感,可是我在这里大力推崇RAC,由于个人MVVM搭建思路里面会涉及大量的属性绑定、事件传递,我可不想写上一万个协议来实现这些简单的功能,运用RAC能大量简化代码,使逻辑更加的清晰。框架
接下来我将对个人MVVM架构实现思路作一个详细的讲解,在这以前,若是你没有用过RAC,请先移步:ide
大体的了解一下RAC事后,即可以往下(^)模块化
这是要实现的界面:
AF45BFF3B07B52D222AF90AE1CCBAC18.png
这里我弱化了Model的做用,它只是做为一个网络请求数据的中转站,只有在View须要显示网络数据的时候,对应的ViewModel里面才有Model的相关处理。
在实际开发当中,一个View对应一个ViewModel,主View对应而且绑定一个主ViewModel。
主ViewModel承担了网络请求、点击事件协议、初始化子ViewModel而且给子ViewModel的属性赋初值;网络请求成功返回数据事后,主ViewModel还须要给子ViewModel的属性赋予新的值。
主ViewModel的观感是这样的:
@interface MineViewModel : NSObject //viewModel @property (nonatomic, strong) MineHeaderViewModel *mineHeaderViewModel; @property (nonatomic, strong) NSArray<MineTopCollectionViewCellViewModel *> *dataSorceOfMineTopCollectionViewCell; @property (nonatomic, strong) NSArray<MineDownCollectionViewCellViewModel *> *dataSorceOfMineDownCollectionViewCell; //RACCommand @property (nonatomic, strong) RACCommand *autoLoginCommand; //RACSubject @property (nonatomic, strong) RACSubject *pushSubject; @end
其中,RACCommand是放网络请求的地方,RACSubject至关于协议,这里用于点击事件的代理,而ViewModel下面的一个ViewModel属性和三个装有ViewModel的数组我须要着重说一下。
在iOS开发中,咱们一般会自定义View,而自定义的View有多是继承自UICollectionviewCell(UITableViewCell、UITableViewHeaderFooterView等),当咱们自定义一个View的时候,这个View不须要复用且只有一个,咱们就在主ViewModel声明一个子ViewModel属性,当咱们自定义一个须要复用的cell、item、headerView等的时候,咱们就在主ViewModel中声明数组属性,用于储存复用的cell、item的ViewModel,中心思想仍然是一个View对应一个ViewModel。
在.m文件中,对这些属性作懒加载处理,而且将RACCommand和RACSubject配置好,方便以后在须要的时候触发以及调用,代码以下:
@implementation MineViewModel
- (instancetype)init { self = [super init]; if (self) { [self initialize]; } return self; } - (void)initialize { [self.autoLoginCommand.executionSignals.switchToLatest subscribeNext:^(id responds) { //处理网络请求数据 ...... }]; } #pragma mark *** getter *** - (RACSubject *)pushSubject { if (!_pushSubject) { _pushSubject = [RACSubject subject]; } return _pushSubject; } - (RACCommand *)autoLoginCommand { if (!_autoLoginCommand) { _autoLoginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSDictionary *paramDic = @{......}; [Network start:paramDic success:^(id datas) { [subscriber sendNext:datas]; [subscriber sendCompleted]; } failure:^(NSString *errorMsg) { [subscriber sendNext:errorMsg]; [subscriber sendCompleted]; }]; return nil; }]; }]; } return _autoLoginCommand; } - (MineHeaderViewModel *)mineHeaderViewModel { if (!_mineHeaderViewModel) { _mineHeaderViewModel = [MineHeaderViewModel new]; _mineHeaderViewModel.headerBackgroundImage = [UIImage imageNamed:@"BG"]; _mineHeaderViewModel.headerImageUrlStr = nil; [[[RACObserve([LoginBackInfoModel shareLoginBackInfoModel], headimg) distinctUntilChanged] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) { if (x == nil) { _mineHeaderViewModel.headerImageUrlStr = nil; } else { _mineHeaderViewModel.headerImageUrlStr = x; } }]; ...... return _mineHeaderViewModel; } - (NSArray<MineTopCollectionViewCellViewModel *> *)dataSorceOfMineTopCollectionViewCell { if (!_dataSorceOfMineTopCollectionViewCell) { MineTopCollectionViewCellViewModel *model1 = [MineTopCollectionViewCellViewModel new]; MineTopCollectionViewCellViewModel *model2 = [MineTopCollectionViewCellViewModel new]; ...... _dataSorceOfMineTopCollectionViewCell = @[model1, model2]; } return _dataSorceOfMineTopCollectionViewCell; } - (NSArray<MineDownCollectionViewCellViewModel *