剖析iOS设计模式MVVM
2018-02-08 03:27
316 查看
设计模式MVVM的由来
众所周知,面向对象,是由面向过程演变而来,于是有了设计模式。客服端编程离不开MVC(model-view-controller)设计模式,由于复杂页面(如微博列表,存在用户表头,内容Cell存在多态及变高,多种操作交杂的情况) 把页面展示,及操作都放在ViewController里进行管理,势必造成ViewController非常庞大,难以阅读及驾驭,从而导致编程效率下降。于是衍生出MVC的很多变种,主要有MVCS(view<->controller<->store<-model)/
MVP(model<->presenter<->conterller<->view),
MVVM(view<->controller<->viewModel<->model)
所以Controller在MVVM中,一方面负责View和ViewModel之间的绑定,另一方面也负责常规的UI逻辑处理。通常较复杂页面使用MVVM,比如变高,多态的列表。
用RAC实现MVVM架构里的登录页面
实现分析
1、ViewModel使用组合信号订阅组合信号2、Controller绑定视图和相关属性,发送命令
3、相关代码demo
RAC在MVVM架构里的使用
1、函数响应式(FRP)替代OC基本语法
a、代替代理:RACSubject-(void)demo1{ [[_blueView rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(RACTuple * _Nullable x) { NSLog(@"%@",x); }]; }
b、代替KVO
-(void)demo2{ [_blueView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { //回调 NSLog(@"value%@---%@",value,change); }]; // _blueView.frame = CGRectMake(0, 0, 100, 100); // 直接定义更爽!!! // [[_blueView rac_valuesForKeyPath:@"frame" observer:self] subscribeNext:^(id _Nullable x) { // NSLog(@"%@",x); // // }]; }
c.监听事件
-(void)demo3{ [[_btn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) { NSLog(@"%@",x); }]; }
d.代替通知
-(void)demo4{ [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) { NSLog(@"%@",x); }]; }
e.监听文本框
-(void)demo5{ [_textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) { NSLog(@"%@",x); }]; }
2、rac_lift替代GCD,dispatch_group_async
解决一个页面多个请求的情况,dispatch_group_async和信号量dispatch_semaphore_t的配合使用无疑比较繁琐,可详见我之前的博文信号量dispatch_semaphore在iOS APP编程里的“应用”,rac_lift代码如下:- (void)rac_liftDemo{ //请求1 RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { //发送请求 NSLog(@"请求网络数据 1"); //发送数据 [subscriber sendNext:@"数据1 来了"]; return nil; }]; //请求2 RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { //发送请求 NSLog(@"请求网络数据 2"); //发送数据 [subscriber sendNext:@"数据2 来了"]; return nil; }]; //数组:存放信号 //当数组中的所有洗好都发送了数据,才会执行Selector //方法的参数:必须和数组的信号一一对应!! //方法的参数:就是每一个信号发送的数据!! [self rac_liftSelector:@selector(updateUIWithOneData:TwoData:) withSignalsFromArray:@[signal1,signal2]]; } - (void)updateUIWithOneData:(id )oneData TwoData:(id )twoData { NSLog(@"%@",[NSThread currentThread]); //拿到数据更新UI NSLog(@"UI!!%@%@",oneData,twoData); }
3、绑定及命令
a、绑定- (void)RACObserverDemo{ //只要这个对象的属性发生变化..哥么信号就发送数据!! [RACObserve(self.label, text) subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; } - (void)RACDemo{ //监听文本框内容 // [_textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) { // _label.text = x; // }]; //给某个对象的某个属性绑定信号,一旦信号产生数据,就会将内容赋值给属性! RAC(_label,text) = _textField.rac_textSignal; } - (void)mapDemo{ //创建信号 RACSubject * subject = [RACSubject subject]; //绑定 [[subject map:^id _Nullable(id _Nullable value) { //返回的数据就是需要处理的数据 return [NSString stringWithFormat:@"处理数据%@",value]; }] subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //发送数据 [subject sendNext:@"123"]; [subject sendNext:@"321"]; } - (void)flattenMapDemo{ //创建信号 RACSubject * subject = [RACSubject subject]; //绑定信号 RACSignal * bindSignal = [subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) { //block:只要源信号发送内容就会调用 //value:就是源信号发送的内容 value = [NSString stringWithFormat:@"处理数据:%@",value]; //返回信号用来包装修改过的内容 return [RACReturnSignal return:value]; }]; //订阅绑定信号 [bindSignal subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //发送数据 [subject sendNext:@"123"]; }
b、命令
- (void)RACSubjectBind{ //1.创建信号 RACSubject * subject = [RACSubject subject]; //2.绑定信号 RACSignal * bindSignal = [subject bind:^RACSignalBindBlock _Nonnull{ return ^RACSignal * (id value, BOOL *stop){ //block调用:只要源信号发送数据,就会调用bindBlock //block作用:处理原信号内容 //value:源信号发送的内容 NSLog(@"%@",value); //返回信号,不能传nil , 返回空信号 :[RACSignal empty] return [RACReturnSignal return:value]; }; }]; //3.订阅信号 [bindSignal subscribeNext:^(id _Nullable x) { NSLog(@"绑定接收到!! %@",x); }]; //4.发送 [subject sendNext:@"发送原始的数据"]; } - (void)RACCommand{ //RACCommand 命令 //1.创建命令 RACCommand * command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) { NSLog(@"%@",input); //input:指令 return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { //发送数据 [subscriber sendNext:@"执行完命令之后产生的数据"]; //发送完成 [subscriber sendCompleted]; return nil; }]; }]; //监听事件有没有执行完毕 [command.executing subscribeNext:^(NSNumber * _Nullable x) { if([x boolValue]){ //正在执行!! NSLog(@"正在执行!!"); }else{ NSLog(@"已经结束咯&&还没开始做!"); } }]; RACSignal * signal = [command execute:@"执行!!"]; [signal subscribeNext:^(id _Nullable x) { NSLog(@"接受到数据了!!%@",x); }]; } -(void)switchToLatestDemo{ //创建多个信号 RACSubject * signalOfSignal = [RACSubject subject]; RACSubject * signal1 = [RACSubject subject]; RACSubject * signal2 = [RACSubject subject]; RACSubject * signal3 = [RACSubject subject]; //订阅信号 // [signalOfSignal subscribeNext:^(id _Nullable x) { // [x subscribeNext:^(id _Nullable x) { // NSLog(@"%@",x); // }]; // }]; //switchToLatest :最新的信号!! [signalOfSignal.switchToLatest subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //发送信号 [signalOfSignal sendNext:signal1]; [signalOfSignal sendNext:signal2]; [signalOfSignal sendNext:signal3]; //发送数据 [signal3 sendNext:@"3"]; [signal2 sendNext:@"2"]; [signal1 sendNext:@"1"]; } -(void)commandDemo2{ //RACCommand 命令 //1.创建命令 RACCommand * command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) { NSLog(@"%@",input); //input:指令 return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { //发送数据 [subscriber sendNext:@"执行完命令之后产生的数据"]; return nil; }]; }]; //订阅信号 //executionSignals:信号源!!,发送信号的信号! // [command.executionSignals subscribeNext:^(RACSignal * x) { // [x subscribeNext:^(id _Nullable x) { // NSLog(@"%@",x); // }]; // NSLog(@"%@",x); // }]; //switchToLatest 获取最新发送的信号. [command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //2.执行命令 [command execute:@"输入的指令!!"]; } -(void)commandDemo1{ //1.创建命令 RACCommand * command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) { NSLog(@"%@",input); //input:指令 // return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { //发送数据 [subscriber sendNext:@"执行完命令之后产生的数据"]; return nil; }]; }]; //2.执行命令 RACSignal * signal = [command execute:@"输入的指令!!"]; //3.订阅信号! [signal subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; }
4信号组合
- (void)zipDemo{ //zipWith:两个信号压缩!只有当两个信号同时发出信号内容,并且将内容合并成为一个元祖给你 //创建信号 RACSubject * signalA = [RACSubject subject]; RACSubject * signalB = [RACSubject subject]; //压缩 RACSignal * zipSignal = [signalA zipWith:signalB]; //接受数据 和发送顺序无关!! [zipSignal subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //发送数据 [signalB sendNext:@"B"]; [signalA sendNext:@"A"]; [signalB sendNext:@"B1"]; [signalA sendNext:@"A1"]; [signalB sendNext:@"B2"]; [signalA sendNext:@"A2"]; } - (void)mergeDemo{ //创建信号 RACSubject * signalA = [RACSubject subject]; RACSubject * signalB = [RACSubject subject]; RACSubject * signalC = [RACSubject subject]; //组合信号 // RACSignal * mergeSignal = [signalA merge:signalB]; RACSignal * mergeSignal = [RACSignal merge:@[signalA,signalB,signalC]]; //订阅 -- 根据发送的情况接受数据!! [mergeSignal subscribeNext:^(id _Nullable x) { //任意一二信号发送内容就会来这个Block NSLog(@"%@",x); }]; //发送数据 [signalC sendNext:@"数据C"]; [signalA sendNext:@"数据A"]; [signalB sendNext:@"数据B"]; } -(void)thenDemo{ //创建信号!! RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"发送请求A"); //发送数据 [subscriber sendNext:@"数据A"]; [subscriber sendCompleted]; return nil; }]; RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"发送请求B"); //发送数据 [subscriber sendNext:@"数据B"]; [subscriber sendCompleted]; return nil; }]; //then:忽略掉第一个信号所有的值!! RACSignal * thenSignal = [signalA then:^RACSignal * _Nonnull{ return signalB; }]; //订阅信号 [thenSignal subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; } - (void)concatDemo{ //组合!! //创建信号!! RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"发送请求A"); //发送数据 [subscriber sendNext:@"数据A"]; //哥么结束了!! [subscriber sendCompleted]; // [subscriber sendError:nil]; 这哥么不行! return nil; }]; RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"发送请求B"); //发送数据 [subscriber sendNext:@"数据B"]; [subscriber sendCompleted]; return nil; }]; RACSignal * signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"发送请求C"); //发送数据 [subscriber sendNext:@"数据C"]; return nil; }]; //concat:按顺序组合!! //创建组合信号!! // RACSignal * concatSignal = [[signalA concat:signalB] concat:signalC]; RACSignal * concatSignal = [RACSignal concat:@[signalA,signalB,signalC]]; //订阅组合信号 [concatSignal subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; }
5信号忽略
- (void)skipDemo { RACSubject * subject = [RACSubject subject]; //skip: 跳跃几个值 [[subject skip:2] subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; [subject sendNext:@"1"]; [subject sendNext:@"2"]; [subject sendNext:@"3"]; } - (void)distinDemo{ //1.创建信号 RACSubject * subject = [RACSubject subject]; //忽略掉重复数据 [[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //请求回来 [subject sendNext:@"abc haha hehe"]; [subject sendNext:@"hehe"]; [subject sendNext:@"1"];[subject sendNext:@"1"]; [subject sendNext:@"2"]; [subject sendNext:@"2"]; } -(void)takeDemo{ RACSubject * subject = [RACSubject subject]; //take:指定拿前面的哪几条数据!!(从前往后) //takeLast:指定拿前面的哪几条数据!!(从后往前)注意点:一定要写结束!! [[subject takeLast:2] subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; [subject sendNext:@"2"]; [subject sendNext:@"3"]; [subject sendNext:@"1"]; [subject sendCompleted]; // RACSubject * subject = [RACSubject subject]; //专门做一个标记信号!! RACSubject * signal = [RACSubject subject]; //take:指定拿前面的哪几条数据!!(从前往后) //takeLast:指定拿前面的哪几条数据!!(从后往前)注意点:一定要写结束!! //takeUntil:直到你的标记信号发送数据的时候结束!!! [[subject takeUntil:signal] subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; [subject sendNext:@"2"]; //[signal sendNext:@".."]; [signal sendCompleted];//标记信号!! [subject sendNext:@"3"]; [subject sendNext:@"1"]; [subject sendCompleted]; } -(void)ignoreDemo{ //ignore:忽略 RACSubject * subject = [RACSubject subject]; //忽略一些值!! RACSignal * ignoreSignal = [[[subject ignore:@"1"] ignore:@"2"] ignore:@"3"]; //订阅 [ignoreSignal subscribeNext:^(id _Nullable x) { NSLog(@"%@",x); }]; //发送数据 [subject sendNext:@"1"]; [subject sendNext:@"2"]; [subject sendNext:@"13"]; [subject sendNext:@"3"]; } -(void)filterDemo{ [[_textfiled.rac_textSignal filter:^BOOL(NSString * _Nullable value) { //value:源信号的内容 return [value length] > 5; //返回值:就是过滤条件,只有满足这个条件,才能获取到内容 }] subscribeNext:^(NSString * _Nullable x) { NSLog(@"%@",x); }]; }
剖析MVVM
参考1、参考2、参考3相关文章推荐
- iOS-MVVM设计模式
- ios开发中的基本设计模式(代理,观察者,MVC,单例,策略,工厂,MVVM,原型,Target-Action,通知(notification)机制)
- iOS开发之MVVM设计模式
- iOS——MVVM设计模式
- iOS-MVVM设计模式
- iOS设计模式--MVVM
- iOS 基于MVVM设计模式的微信朋友圈开发
- iOS MVC设计模式与MVVM设计模式简介 —— HERO博客
- iOS-MVVM设计模式
- iOSMVVM(Model-View(View/ViewController) -ViewModel ) 设计模式
- iOS 基于MVVM设计模式的微信朋友圈开发
- iOS 引入MVVM 设计模式
- iOS开发 —— MVVM设计模式
- iOS开发之有趣的UI —— MVVM设计模式
- iOS 基于MVVM设计模式的微信朋友圈开发
- iOS设计模式——MVVM模式
- iOS中的MVVM设计模式
- iOS MVVM设计模式
- ios 设计模式 MVC ,MVVM
- iOS MVVM设计模式