首先来对比一下常用的几种架构,这里列举三种,MVC,MVP,MVVM架构,MVC架构属于最经典的一种架构,M相当于Model层,负责处理数据相关的操作,V属于View层,负责各种UI的展示和用户交互,C属于Controller控制器,属于协调M层和V层,对于简单的项目来说,使用MVC架构模式已经绰绰有余,但是随着项目的不断变大,功能不断增多,参与项目的人员的更替,会发现,大量的业务逻辑是放在C层,而且不同人的编程习惯不一样,当复杂的业务逻辑加上庞大的功能划分叠加在一起的时候,会发现我们的C层早已臃肿不堪,摇摇欲坠了,这个时候代码想要前进,唯一的办法就是替换当前架构模式。
这里就先引入MVP架构,百度一下会看到这样一句话:MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示,这个架构其实是多出了一层(P层)来帮助C层处理业务逻辑,这样做的好处显而易见,C层肩上的担子明显轻了很多,而且很多业务逻辑可以丢到P层来处理,一般项目可以使用这中架构模式,但是随着开发的脚步不断向前迈进,你会发现P层和C层过于亲密,频繁的交互高度耦合,当我们的需求变更时,P层也更作开始大变更,对于大型项目或者拓展性要求较高的项目,MVP架构明显不能完成胜任,接下来,我们一起看看今天的重点,MVVM架构模式。
MVVM架构,继续百度吧,MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。进一步百度WPF,可以看到在技术层面,WPF带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性,其实说到底就是一种信号绑定数据的模式,所有的数据都在信号里面执行,再由信号传递出来,优点很明显,低耦合,可重用,没个人可以写自己的ViewModel模块而不影响别人的代码。
之前一篇文章已经讲了一部分的RAC用法,接下来我们继续进入RAC的使用,当你掌握它之后,我敢相信你已经深深爱上了RAC,因为它太神奇了,来,干!!!!
应用场景: 当我们请求到数据后,如果几个地方都需要用到这个数据,如何避免多次使用,但请求就只有一次?
// 1. 创建信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id_Nonnull subscriber) {
// 请求数据
NSLog(@"请求数据");
// 发送数据
[subscriber sendNext:@"发送数据"];
return nil;
}];
// 2.转换信号
RACMulticastConnection *connection = [signal publish];
// 3.开始订阅
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"A处理数据%@",x);
}];
[connection.signal subscribeNext:^(id _Nullable x) {
NSLog(@"B处理数据%@",x);
}];
// 连接
[connection connect];
应用场景二: RACComand,这个类极大的帮我们优化的开发过程中的逻辑,流程:发送指令--->接收指令--->请求数据--->发送数据---->订阅数据(还可以监听事件的执行状态)
// 1.创建命令 RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) { // input: 就是下面的输入的指令 NSLog(@"%@",input); // 返回一个信号 return [RACSignal createSignal:^RACDisposable * _Nullable(id_Nonnull subscriber) {
// 发送数据
[subscriber sendNext:@"执行完命令后,产生的数据"];
// 《如果要监听事件的状态,必须执行事件完成状态》
[subscriber sendCompleted];
return nil;
}];
}];
// 监听事件: 获取命令状态
[command.executing subscribeNext:^(NSNumber * _Nullable x) {
NSLog(@"%@",x);
if ([x boolValue]) {
NSLog(@"正在执行");
} else {
NSLog(@"已经结束和还没开始做");
}
}];
// 执行
RACSignal *signal = [command execute:@"执行"];
// 订阅
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"接收到数据了,%@",x);
}];
应用场景三: 绑定:bind
// 1.创建信号
RACSubject *subject = [RACSubject subject];
// 2.绑定信号
RACSignal *bindSignal = [subject bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id value,BOOL *stop) {
// value 就是“发送原始数据”
NSLog(@"%@",value);
// 应用场景: 可以在这里做字典转模型
// 返回空信号
// return [RACSignal empty];
return [RACReturnSignal return:value];
};
}];
// 3. 订阅信号
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
// 4.发送
[subject sendNext:@"发送原始数据"];
其他场景:
顺序组合 : concat 比较类似于串行队列
返回最后的信号 : then
压缩信号 : zip 只有当多个信号都有发送数据时才会调用
组合 : combineLatest 同时监听多个信号
合并 : merge 任一信号发送数据就会执行,类似并行队列
这里就不上代码了,只需要知道有这些个类型,及用法,到时候根据需要自行百度就好。
最后,就如何结合MVVM实际用法,简单谈下方法,由于C层只要求展示UI和用户交互外,可以处理非常简单的逻辑外,其余的事情我们直接交给ViewModel层来处理,可以在ViewModel里面设置各种信号属性,同时让C层持有ViewModel作为属性,在事件需要处理时,使用RACComand或者RACSubject或者RACSignal来将事件转化成信号。
另外需要特别主要的是:
1.输入框的信号(比如:让ModelView的属性变化通过RAC宏来绑定C层的输入框的信号)
2.RAC宏的优越性