ReactiveCocoa

目录

一、ReactiveCocoa结合了多种编程风格

二、在MVVM的项目中,为何总是会提到RAC呢?

三、ReactiveCocoa一些概念和用法


之前使用ReactiveCocoa+MVVM做过一次项目,当时使用它的原因就是感觉一个是新,一个是非常的简洁,看起来很酷。

当时别人问我ReactiveCocoa是什么,我都会回答:函数响应式编程。当时也不懂什么意思,那么现在再来回顾一下ReactiveCocoa。

一、ReactiveCocoa结合了多种编程风格:

函数式编程(Functional Programming)

函数式编程思想:是把操作尽量写成一系列嵌套的函数或者方法调用。

响应式编程(Reactive Programming)

响应式编程思想:不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果。

那么我们简单举个例子:

RACSignal *signalA = RACObserve(self, a);

RACSignal *signalB = RACObserve(self, b);

RAC(self.label, text) = [RACSignal combineLatest:@[signalA,signalB] reduce:^(NSInteger countA, NSInteger countB){

return [NSString stringWithFormat:@"结果:%ld",countA+countB];

}];


那看看我们通常的做法

- (void)sumAction

{

self.label.text = [NSString stringWithFormat:@"结果:%ld",self.a+self.b];

}

看起来这个操作放在了一个方法中,挺简单的,可是每次调用self.a = X;或者self.b = Y;时,想要显示正确的值,那么必定要再调用一次[self sumAction];

当我们执行顺序为self.a = X; [self sumAction]; self.b = Y; 这个时候没有得到我们想要的X+Y的值,这不是响应式的。

如果我们将[self sumAction];的调用放在set方法中呢?那么确实是响应式的了,但用到了至少两个方法。

在MVVM的项目中,为何总是会提到RAC呢?

MVVM从MVC演化而来,为的是减少C的逻辑和业务。如果没有RAC,那么我们得使用NSNotification、delegate、KVO等将V变化产生的数据传给VM,从而改变M的值。NSNotification可能跨度大点,尤其delegate和KVO会免不了将业务再次放到C中,如果不放到C中,那么这个VM就会与这个View绑定得比较紧,而ViewModel有可能并不是只服务于特定的一个View,这样的话使用更加松散的绑定关系能够降低ViewModel和View之间的耦合度。

因此View一旦产生数据了扔信号扔给ViewModel,使用ReactiveCocoa更能体现其精髓。

注:大部分MVVM架构都会使用ReactiveCocoa,但是使用ReactiveCocoa的iOS应用不一定就是基于MVVM架构的。MVVM的关键是要有View Model。


三、ReactiveCocoa一些概念和用法:

1.map:

map是将一张表中的值映射新值到另一张表中

NSArray*mappedArray=[array rx_mapWithBlock:^id(ideach){

return @(pow([each integerValue], 2));

}];

注:这是建立了一个新的数组,而不是将原数组的值进行改变

这所对应的是

NSMutableArray*mutableArray=[NSMutableArrayarrayWithCapacity:array.count];

for(NSNumber*numberinarray){[mutableArrayaddObject:@(pow([number integerValue], 2))];

}

NSArray*mappedArray=[NSArrayarrayWithArray:mutableArray];

这就是更高级别的函数更占优势的地方

2.filter(过滤)

3.fold(结合)

//合数值

NSNumber*sum=[array rx_foldWithBlock:^id(id memo,id each){

return @([memo integerValue] +  [eachintegerValue]);

}];

//拼字符串

[[array rx_mapWithBlock:^id(id each){

return [each stringValue];

}] rx_foldInitialValue:@""block:^id(id memo,id each){

return [memo stringByAppendingString:each];

}];

4.Streams and Sequences

一系列的值抽象的被称为流,你可以认为流就像一个管道,其中值从一端进入从另一端放出。除非在管道的尾端当值出来时你能访问,访问过去的值甚至是当前值都是不可能的。没关系,我们拭目以待。

一系列的值,是吗?有点像一个列表,或在我们的例子中,一个数组。事实上,我们可以使用rac_sequence方法很容易地将一个NSArray转化成流。

NSArray*array=@[@(1),@(2),@(3)];

RACSequence*stream=[array rac_sequence];//将数组转化成流

[stream map:^id(id value){

return @(pow([value integerValue],2));

}];

NSLog(@"%@",[stream array]);//将流又转化成数组

//原来项目中使用了这个方法是这样的一个过程,map可以将字典转化成对象,然后就成为了对象的数组

NSLog(@"%@",[[[array rac_sequence] map:^id(idvalue){

return @(pow([value integerValue],2));

}] array]);

ReactiveCocoa包含left fold和right fold。left

fold是从开始往结尾穿过一个数组,right fold是反的

5.Signals

信号是另一种类型的流,对比sequences(序列),信号是推驱动,新值通过管道推压并且不能拉出,在以后他们把将被递送的数据抽取出来。

信号包括三种不同的类型值:Next、Error、Completion.

值得注意的是,Error和Completion只能通过信号送出一次,并且只有一个被送出。

6.Subscriptions

[self.textField.rac_textSignal subscribeNext:^(id x){

NSLog(@"New value:%@", x);

}error:^(NSError*error){

NSLog(@"Error: %@",error);

}completed:^{

NSLog(@"Completed.");

}];

在textfield中输入字符时,发现信号不发送error值和当信号deallocated的时候发送completion值,因此我们可以

[self.textField.rac_textSignal subscribeNext:^(idx){

NSLog(@"New value: %@", x);

}];

当subscribe(订阅)一个信号,将自动创建一个subscription对象,这个对象将自动保留,同时也保留了这个信号的subscribing状态,你可以手动处理订阅者,但这不是典型的操作,一般在使用重用视图的时候处理信号

7.Deriving State

宏RAC()有两个参数:一个对象和该对象的键值路径。然后,它执行一个单向的绑定右边的值到键值路径。值必须是对象,这就是为什么我们把布尔值包装成一个NSNumber。

RACSignal *validEmailSignal=[self.textField.rac_textSignalmap:^id(NSString *value){

return @([value rangeOfString:@"@"].location!= NSNotFound);

}];

RAC(self.button,enabled)=validEmailSignal;

RAC(self.textField,textColor)=[validEmailSignalmap:^id(id value){

if ([value boolValue]) {           return [UIColor greenColor];

} else {

return [UIColor redColor];

}

}];

8.Commands

当你想要发送一个信号的值对用户交互事件响应,Commands是有用的。command的信号能被订阅来稍后接收返回的输出信号。

self.button.rac_command= [[RACCommand alloc]initWithEnabled:validEmailSignal

signalBlock:^RACSignal *(idinput){

NSLog(@"Button was pressed.");

return [RACSignal empty];

}];

这个按钮将保持disabled直到信号返回complete值(也可以是空值([RACSignal empty]))

9.RACSubject

信号提供者,自己可以充当信号,又能发送信号。

创建方法:

(1)创建RACSubject

(2)订阅信号

(3)发送信号

工作流程:

(1)订阅信号时,内部保存了订阅者,和订阅者响应block

(2)当发送信号的,遍历订阅者,调用订阅者的nextBlock

注:如果订阅信号,必须在发送信号之前订阅信号,不然收不到信号,这也有别于RACReplaySubject

-(void)racSubjectTest

{

RACSubject *subject= [RACSubjectsubject];

[subject subscribeNext:^(idx) {

NSLog(@"1

%@,type:%@",x,NSStringFromClass(object_getClass(x)));

}];

[subject subscribeNext:^(idx) {

NSLog(@"2

%@,type:%@",x,NSStringFromClass(object_getClass(x)));

}];

[subjectsendNext:@1];

[subject subscribeNext:^(idx) {

NSLog(@"3

%@,type:%@",x,NSStringFromClass(object_getClass(x)));

}];

}

10.Hot and Cold Signals

信号通常是懒惰的,意味着它们只有在有人已经订阅它们的时候,它们才会工作和发送信号。每增加一个订阅,工作就会重新执行。对于繁琐的操作,这是可以接受的,并且实际上这是所希望的。在ReactiveCocoa术语中,这种类型的信号被称为“冷信号”。

有时,我们想工作立即被执行,这种类型的信号被称为“热信号”。热信号非常罕见被使用到。

11.Multicasting

Multicasting是指某个信号订阅被共享于大量订阅者的术语。信号,一般是“冷信号”,它有时是不可取的,执行工作每次它都是订阅的“冷信号”,这常常是当副作用或工作时订阅是昂贵的时候执行,否则只有在适当的时候才会执行。网络请求浮现在脑海中。

于是我们创建来源于信号的RACMulticastConnection。你可以在RACSignal中使用publish方法或multicast:方法。前一种方法为您创建一个multicast的连接。后一种方法也做了同样的事,但还采用RACSubject参数。这个subject是手动从底层信号发送值,每当它被调用。然后,任何由底层信号发送的值有兴趣订阅连接的信号,相反(如果你提供一个subject,信号正好是这个subject)。

由于在默认情况下信号是“冷信号”,每添加一个订阅者,则它的工作被执行。如果是这样的话,那是不可取的,我们使用multicast的连接。

multicast的连接订阅的信号,当它已经通过了新的值,发送这些值到信号(这作为一个公共属性公开)。你可以多次订阅这个信号,并且在订阅时执行的工作,只是一次

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容