ReactiveCocoa 谈谈concat
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了ReactiveCocoa 谈谈concat,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6817字,纯文字阅读大概需要10分钟。
内容图文
今天的一个业务流程,业务流程大概就是这样的
1.从CoreData中获取之前的数据
2.更新界面
3.从网络获取数据
4.判断获取结果
5.处理错误判断
6.更新界面
7.判断结果numberOfNews字段
8.现实numberOfNews信息
这种顺序行的处理,正正是ReactiveCocoa的擅长解决的问题,那么问题来了,怎么才能通过Signal,将if else 转换数据,要知道,很多地方都在block里面
这就需要用到flattenMap 和 then 这两个东西
来看看React的玩法
1 // 1.从CoreData中获取数据 2 RACSignal *local = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 3//1.1 获取完成后通知下一步 4 [subscriber sendNext:nil]; 5 [subscriber sendCompleted]; 6return nil; 7 }]; 8 9//2.转换数据,这个过程没有理由在mainThread中进行的10 RACSignal *viewModel = [[local subscribeOn:[RACScheduler scheduler]] map:^id(id value) { 11//1.2 将CoreDataModel转换成视图模型12return nil; 13 }]; 1415//3.显示到界面中16 [viewModel subscribeNext:^(id x) { 171819 }]; 2021//4.创建一个网络请求22 RACSignal *request = [viewModel then:^RACSignal *{ 23return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 2425 NSURLSessionTask *task = nil;//这里新建一个网络请求2627return [RACDisposable disposableWithBlock:^{ 28if (task.state != NSURLSessionTaskStateCompleted) { 29 [task cancel]; 30 } 31 }]; 3233 }]; 3435 }]; 36373839//5.避免重复请求,使用MutileConnection转换Signal40 RACMulticastConnection *requestMutilConnection = [request multicast:[RACReplaySubject subject]]; 41 [requestMutilConnection connect]; 4243//6.处理服务器结果44 RACSignal *response = [request flattenMap:^RACStream *(id value) { 45//比如response中包含一个state 的枚举字段,判断这货是返回是否有效请求 4647// return [RACSignal return:value];48return [RACSignal error:value]; 49 }]; 5051//7.更新界面52 [response subscribeNext:^(id x) { 53//再次更新界面54 }]; 5556//8.处理错误57 [response subscribeError:^(NSError *error) { 58//处理错误59 }];
当然,为了简化,里面留了个坑,并且省略许多逻辑代码
回到正题,concat 是 RACSignal 的一个实例方法
在源码实现如下
- (RACSignal *)concat:(RACSignal *)signal { return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) { RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init]; RACDisposable *sourceDisposable = [self subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{ RACDisposable *concattedDisposable = [signal subscribe:subscriber]; serialDisposable.disposable = concattedDisposable; }]; serialDisposable.disposable = sourceDisposable; return serialDisposable; }] setNameWithFormat:@"[%@] -concat: %@", self.name, signal]; }
上面的代码
1.创建一个新的信号
2.在原来的信号中订阅subscribeNext 并在completed block中将新建的Signal的subscriber传入到我们concat的信号
这里非常容易理解为什么可以在上一个信号完成时接着调用下一个信号,原因就在 signal subscribe:subscriber这里啊
但是事情并非这么简单
再看看如果使用concat 时会怎么样
一个非常简单粗暴的代码段
1 RACSignal *fristSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 2 3 NSLog(@"oneSignal createSignal"); 4 [subscriber sendNext:@""]; 5 [subscriber sendCompleted]; 6 7return [RACDisposable disposableWithBlock:^{ 8 NSLog(@"oneSignal dispose"); 9 }]; 10 }]; 1112 RACMulticastConnection *connection = [fristSignal multicast:[RACReplaySubject subject]]; 1314 [connection connect]; 1516 [connection.signal subscribeNext:^(id x) { 17 NSLog(@"2"); 18 }]; 192021 RACSignal *afterConcat = [connection.signal concat:[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 22 [subscriber sendNext:@""]; 23return nil; 24 }]]; 2526 [afterConcat subscribeNext:^(id x) { 27 NSLog(@"afterConcat subscribeNext"); 28 }];
输出结果
2015-10-15 23:00:26.998 conatAndThen[3814:2388477] oneSignal createSignal 2015-10-15 23:00:26.999 conatAndThen[3814:2388477] oneSignal dispose 2015-10-15 23:00:27.001 conatAndThen[3814:2388477] 2 2015-10-15 23:00:27.001 conatAndThen[3814:2388477] afterConcat subscribeNext 2015-10-15 23:00:27.002 conatAndThen[3814:2388477] afterConcat subscribeNext
afterConcat 的 subscribNext被调用了两次!!!
在来看看then
1 RACSignal *fristSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 2 3 NSLog(@"oneSignal createSignal"); 4 [subscriber sendNext:@""]; 5 [subscriber sendCompleted]; 6 7return [RACDisposable disposableWithBlock:^{ 8 NSLog(@"oneSignal dispose"); 9 }]; 10 }]; 1112 RACMulticastConnection *connection = [fristSignal multicast:[RACReplaySubject subject]]; 1314 [connection connect]; 1516 [connection.signal subscribeNext:^(id x) { 17 NSLog(@"2"); 18 }]; 192021 RACSignal *then = [connection.signal then:^RACSignal *{ 2223return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 24 [subscriber sendNext:@""]; 25return nil; 26 }]; 2728 }]; 2930 [then subscribeNext:^(id x) { 31 NSLog(@"then subscribNext"); 32 }];
输出结果
2015-10-15 23:02:40.746 conatAndThen[3848:2419019] oneSignal createSignal 2015-10-15 23:02:40.747 conatAndThen[3848:2419019] oneSignal dispose 2015-10-15 23:02:40.748 conatAndThen[3848:2419019] 2 2015-10-15 23:02:40.750 conatAndThen[3848:2419019] then subscribNext
这才是我们想要的结果
then 实际上是对 concat 的包装
我们看看源码是怎么避免重复执行的
- (RACSignal *)then:(RACSignal * (^)(void))block { NSCParameterAssert(block != nil); return [[[self ignoreValues] concat:[RACSignal defer:block]] setNameWithFormat:@"[%@] -then:", self.name]; }
关键就在ignoreValues 方法中
- (RACSignal *)ignoreValues { return [[self filter:^(id _) { return NO; }] setNameWithFormat:@"[%@] -ignoreValues", self.name]; }
为了证明我的猜想,在demo中concat前filter一次
RACSignal *afterConcat = [[connection.signal filter:^BOOL(id value) { return NO; }] concat:[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@""]; return nil; }]];
结果如下
2015-10-15 23:09:51.013 conatAndThen[3967:2511660] oneSignal createSignal 2015-10-15 23:09:51.013 conatAndThen[3967:2511660] oneSignal dispose 2015-10-15 23:09:51.015 conatAndThen[3967:2511660] 2 2015-10-15 23:09:51.016 conatAndThen[3967:2511660] afterConcat subscribeNext
更深入的问题来了,为什么filter一次就可以避免重复发送
从源码拷贝出来整理分析
RACSignal *after = [RACSignal createSignal:^(id<RACSubscriber> subscriber) { RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init]; RACDisposable *sourceDisposable = [connection.signal subscribeNext:^(id x) { [subscriber sendNext:x]; } error:^(NSError *error) { [subscriber sendError:error]; } completed:^{
RACDisposable *concattedDisposable = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@""];//试试把这个注释, after subscribeNext 只会执行一次 return nil; }] subscribe:subscriber]; serialDisposable.disposable = concattedDisposable; }]; serialDisposable.disposable = sourceDisposable; return serialDisposable; }]; [after subscribeNext:^(id x) { NSLog(@"afterConcat subscribeNext"); }];
真相已经出现了
在completed block 中 创建的signal(SA),其subsciber (A)已经变成了外层的Signal 的 subsciber,而 connection.signal 中 的subscribeNext 已经对(A)sendNext 一次,而我们需要concat 的signal 需要通知订阅这 在SA又sendNext一次, 所以 then 的出现就是避免 [subscriber sendNext:x]对外部执行流程的影响
参考文献
https://github.com/ReactiveCocoa/ReactiveCocoa
http://tech.meituan.com/RACSignalSubscription.html
原文:http://www.cnblogs.com/forkasi/p/4883921.html
内容总结
以上是互联网集市为您收集整理的ReactiveCocoa 谈谈concat全部内容,希望文章能够帮你解决ReactiveCocoa 谈谈concat所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。