展会信息港展会大全

Reactive Cocoa 响应式编程开发实例讲解-中篇,reactivecocoa
来源:互联网   发布日期:2015-09-28 13:35:41   浏览:1544次  

导读: Reactive Cocoa 响应式编程开发实例讲解-中篇,reactivecocoa 上一篇文章作为开门篇讲述了Cocoa Reactive概述。 这里我们...

Reactive Cocoa 响应式编程开发实例讲解-中篇,reactivecocoa

上一篇文章作为开门篇讲述了Cocoa Reactive概述。

这里我们详细介绍一下CocoaReative在代码中的应用。

网上好多blog有人形容CocoaReative 中 signals是插座或者水龙头,感觉不是很好理解。我举个更贴近生活的,用电话订菜(餐馆是Signals,电话订阅是SubScriberNext)。

1.概述

Create一个Signal我们视为是一个支持电话订餐的餐馆,他们有很多菜,油盐酱醋就更不用说,当一个电话打进来首先,这个Signal就开始执行,等菜做好了,菜馆要做的是SendNext通知你一下,你呢?就出来拿,或者让他们送来,最后吃掉。分析一下在这期间,可能会有好多订阅者,菜馆只有一个,厨师会源源不断的炒菜(不要说什么如果菜馆没菜怎么办?太坑了),满足所有订阅者(电话预定)的需求。当然如果没人订阅这些配菜不会被炒,都处于配菜状态,所以,这些配菜可以用来组合,过滤什么的,以达到满足用户的口味(SubscriberNext)。怎么样这个举例不知道能否帮助你的理解。

后面的讲述将会拆解步骤来辅助大家理解不同的功能和类、方法。

//我是菜馆,有了我你们才有源源不断的饭菜可以吃

RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

return nil;

}];

//有菜馆的菜单了,开始电话预定

[signal subscribeNext:^(id x){

NSLog(@"客户处理开始吃了:X是菜馆给的%@",x);

}];

这样不知道大家是否明白,反正我是明白了。提一个问题,如果没有电话预定,菜馆能做菜吗?(Signal能触发吗?)答案是:如果不怕赔钱,可以天天做好菜等着(估计没人吃,几天你的菜馆就关门了)。

2.Signals和它的两种状态-冷、热信号(其实就是菜馆有没有生意)

如果菜馆没有接到电话约定是不是生意很冷啊,所以叫做冷信号。如果不停的接单是不是生意红火啊,叫(红火不就是热吗)做热信号。那放到程序中怎么理解:

//我是菜馆,有了我你们才有源源不断的饭菜可以吃

RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

//完成

[subscriber sendCompleted];

return nil;

}];

//如果后面没有订单我的生意怎么做啊!

一个Signal使用CreateSignal创建,这里没什么好讲的记住就可以了。

上面已经说了,如果没有订单我的生意怎么做,这就是冷Signal。

突然有一天,来生意了,结果来了一百个。是不是就火了,这就是热Signal。

//来生意了

//有菜馆的菜单了,开始电话预定

[signal subscribeNext:^(id x){

NSLog(@"客户处理开始吃了");

}];

到这里不知道到家是否有对Signal有个初步的认识,Signal是Reactive的核心,理解了,基本上你就可以驾驭这个框架做你想做的。它不仅仅有SendNext方法,还有

sendNext:其实生活中菜馆是把所有的菜做好了,才打电话通知你,程序中是这样的,超好一个菜就sendNext:客户就吃一个。明白了很像在饭店吃饭(对,就是这样,你就理解是在饭店吃饭(执行Signal),做好一个上一个(SendNext),你吃一个(subscribeNext:))。

sendError: 这个就不用说了,肯定是不好意思,给你炒菜炒错了,现实中,你会想算了,吃吧(是你对错误的处理方式),这个方式只能执行一次(要是多长你还不要了厨师的命啊)。

sendComplete:这个也是执行一次,结账走人了。

//执行一次

[signal subscribeCompleted:^{

NSLog(@"结账走人");

}];

//执行一次

[signal subscribeError:^(NSError *error) {

NSLog(@"算了,人家做生意也不容易,将就吃吧");

}];

这个算是响应式编程吧。大家自己体会,体会不了?不是吧,再举个例子,大家还记我们支付宝在输入密码钱,确定按钮是灰色的对吧,一旦我们输完密码,按钮高亮,这个就是一种信号的响应。不多说了!

3.doNext(打包送一次性筷子)

//我是菜馆,有了我你们才有源源不断的饭菜可以吃

RACSignal *signal = [[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

//完成

[subscriber sendCompleted];

return nil;

}] doNext:^(id x) {

NSLog(@"给点一次筷子什么的,米饭啊");

}];

<pre name="code" class="html">//有菜馆的菜单了,开始电话预定 [signal subscribeNext:^(id x) { NSLog(@"客户处理开始吃了"); }];

doNext 是在信号被处理前,做一些同步修饰工作,比如说送一次性筷子,哈哈,比如你在登陆Signal送出去后,你希望按钮(或者转菊花)现实登陆中....,都可以在这里做掉的。

4.对信号Signal数据的过滤和组合(就是我不吃辣椒,我不吃香菜什么的)

菜馆在做菜的时候肯定都是配好菜的,之后把这些配菜组合过滤,就变成了我们想吃的菜,有人问如何过滤?你喜欢吃香菜吗?喜欢辣椒吗?喜欢大蒜吗?这回知道了吧?那如何反映到Reactivie中呢?

RACSignal *signal = [[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

//完成

[subscriber sendCompleted];

return nil;

}] filter:^BOOL(id value) {//-----------------------------------------新增代码

//过滤辣椒

BOOL noLaJiao = YES;

NSLog(@"过滤辣椒");

return noLaJiao;

}] doNext:^(id x) {

NSLog(@"给点一次筷子什么的,米饭啊");

}];

//订单-<span style="font-family: Arial, Helvetica, sans-serif;">--------------------------------------------------------------如果noLaJiao=NO;你会吃吗?</span>

[signal subscribeNext:^(id x) {

NSLog(@"客户处理开始吃了");

}];

上面代码有什么不同,你一眼就看出来,过滤辣椒,你可以把这个代码copy过去运行一下,你把noLaJiao改成NO试试,你看看订单那部分代码会执行吗?你会吃吗?肯定不会的。这就是过滤filer字面意思你也理解了。

这个地方注意一下他是返回的BOOL值,但是如果我们需要是数据,我们就需要map一次进行数据整合(辣椒给你过滤,菜还要给你做,做好了好吧菜端出去)。

RACSignal *signal = [[[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

//完成

[subscriber sendCompleted];

return nil;

}] filter:^BOOL(id value) {

//过滤辣椒

BOOL noLaJiao = YES;

NSLog(@"过滤辣椒");

return noLaJiao;

}] map:^id(id value) {

NSLog(@"菜加工中......");//-------------------------------------新增代码这个地方开始加工菜了

return value;

}] doNext:^(id x) {

NSLog(@"给点一次筷子什么的,米饭啊");

}];

//订单

[signal subscribeNext:^(id x) {

NSLog(@"客户处理开始吃了");

}];

上面就是对菜信号量的过滤组合处理,我们来看看运行的结果:

2015-02-02 17:08:37.816 TestRAC[5863:192403] 接单了

2015-02-02 17:08:37.816 TestRAC[5863:192403] 处理.....

2015-02-02 17:08:39.649 TestRAC[5863:192403] 过滤辣椒

2015-02-02 17:08:41.016 TestRAC[5863:192403] 菜加工中......

2015-02-02 17:08:42.017 TestRAC[5863:192403] 给点一次筷子什么的,米饭啊

2015-02-02 17:08:42.873 TestRAC[5863:192403] 客户处理开始吃了

5.信号的依赖(就你你想的如果我要辣子鸡,没鸡啊)-- flattenMap处理信号依赖组合

鸡肉对我们来说是数据,我们不需要关心细节,但是鸡对菜馆来说是一个信号,这个菜的依赖性太强,要等到把鸡买来才能做菜,不过这和你没关系。这个过程就是信号依赖。那如何用程序来做呢?

@weakify(self);//--------------------------------1

RACSignal *signal = [[[[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

//完成

[subscriber sendCompleted];

return nil;

}] filter:^BOOL(id value) {

//过滤辣椒

BOOL noLaJiao = YES;

NSLog(@"过滤辣椒");

return noLaJiao;

}] map:^id(id value) {

NSLog(@"菜加工中......");

return value;

}] flattenMap:^RACStream *(id value) {<span style="font-family: Arial, Helvetica, sans-serif;">//--------------------------------2</span>

NSLog(@"我才没鸡了,你怎么不早说....赶紧买鸡去.....");

@strongify(self);//-------------------------------------------------------------3

[self performSelector:@selector(buyChicken) withObject:nil afterDelay:3];//---------------------------4

return [[[self rac_signalForSelector:@selector(buyChicken)] filter:^BOOL(id value) {

BOOL goodChinken=YES;//-----------------------------5

return goodChinken;

}] map:^id(id value) {

return @"买到好鸡了....是白羽鸡......";

}];

}] doNext:^(id x) {

NSLog(@"给点一次筷子什么的,米饭啊");

}];

//订单

[signal subscribeNext:^(id x) {

NSLog(@"客户处理开始吃了-%@",x);

}];

//买鸡过程

- (void) buyChicken

{

NSLog(@"买鸡回去.....买回来了......");

}

运行结果:

2015-02-02 17:28:52.688 TestRAC[5968:201097] 接单了

2015-02-02 17:28:52.689 TestRAC[5968:201097] 处理.....

2015-02-02 17:28:54.777 TestRAC[5968:201097] 过滤辣椒

2015-02-02 17:28:55.992 TestRAC[5968:201097] 菜加工中......

2015-02-02 17:28:55.992 TestRAC[5968:201097] 我才没鸡了,你怎么不早说....赶紧买鸡去.....

2015-02-02 17:29:02.104 TestRAC[5968:201097] 买鸡回去.....买回来了......

2015-02-02 17:29:09.279 TestRAC[5968:201097] 给点一次筷子什么的,米饭啊

2015-02-02 17:29:10.911 TestRAC[5968:201097] 客户处理开始吃了-买到好鸡了....是白羽鸡......

代码假如1-5,weakify和strongify是成对出现,self在block使用容易强饮用,所以这个不多讲,记住就行。格式就是block外一个weakify ,block内多个strongify。

2行代码是对信号依赖的处理,关键字flattenMap。

3模拟买鸡过程用时3秒钟。

4这个是NSObject一个累扩展,这里先不讲,意思说产生一个信号,等信号触发后返回买鸡信号。如果你看不懂你可以这么做:

5就不说了,看一下4改进的代码:

//买鸡信号

RACSignal *buyChinkenSignal = [[[self rac_signalForSelector:@selector(buyChicken)] filter:^BOOL(id value) {

BOOL goodChinken=YES;

return goodChinken;

}] map:^id(id value) {

return @"买到好鸡了....是白羽鸡......";

}];

@weakify(self);

RACSignal *signal = [[[[[RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {

NSLog(@"接单了");

NSLog(@"处理.....");

[subscriber sendNext:@"炒菜完成,打电话给客户"];

//完成

[subscriber sendCompleted];

return nil;

}] filter:^BOOL(id value) {

//过滤辣椒

BOOL noLaJiao = YES;

NSLog(@"过滤辣椒");

return noLaJiao;

}] map:^id(id value) {

NSLog(@"菜加工中......");

return value;

}] flattenMap:^RACStream *(id value) {

NSLog(@"我才没鸡了,你怎么不早说....赶紧买鸡去.....");

@strongify(self);

[self performSelector:@selector(buyChicken) withObject:nil afterDelay:3];

//------------------------------------买鸡信号--------------------------------

return buyChinkenSignal;

}] doNext:^(id x) {

NSLog(@"给点一次筷子什么的,米饭啊");

}];

大家估计理解有点困难,你可以把代码敲下来,运行看看。

好长.....后面在总结........

不同信号组合和控件的使用,信号数据Sequence等。

http://www.bkjia.com/Androidjc/952527.htmlwww.bkjia.comtruehttp://www.bkjia.com/Androidjc/952527.htmlTechArticleReactive Cocoa 响应式编程开发实例讲解-中篇,reactivecocoa 上一篇文章作为开门篇讲述了Cocoa Reactive概述。 这里我们详细介绍一下CocoaReative在...

赞助本站

人工智能实验室

相关热词: android开发 android教程

AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港