您的位置:首页 > 移动开发 > IOS开发

剖析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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息