ReactiveCocoa 信号

信号源

在RAC中,信号源代表等是随着时间而改变的值流,这是对RAC最精准的概括。订阅者可以通过订阅信号源来获取这些值:
Stream of values over time.
你可以把它想象成运送玻璃珠等管道,你打开阀门时,玻璃珠就一个一个的到达。这里玻璃珠就是所需要的值,打开阀门就是订阅它们的过程。

RACSignal

RACSignal 代表的是未来将会被传送的值,RACSignal可以向发送者发送三种不同类型的事件:

  • next:通过next事件向订阅者传送新的值。并且这个值可以为nil;
  • error: 通过error 事件向订阅者表明信号在正常结束前发送错误。
  • completed:通过completed 事件向订阅者表明信号已经正常结束,不会再有后续的值传送给订阅者。

注意:一个信号的生命周期是任意多个next事件和一次error或completed事件组成。

冷信号

冷信号是被动的,只有当你订阅的时候,它才会发送消息。
冷信号是一对一的,当有不同的订阅者,消息是重新完整发送。

//创建一个signal
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"signal 正在被创建");
    [subscriber sendNext:@"1"];
    return nil;
}];
// 以上我们创建了一个signal, 但它并没有被订阅。打印信息如下
//2016-05-23 18:08:05.730 HotColdSignal[2141:456678] signal 创建完成了
 
[signal subscribeNext:^(id x) {
    NSLog(@"我来第一次订阅signal了--%@",x);
}];    
//以上,我们订阅了signal,发现signal 被创建了
//2016-05-23 18:09:51.762 HotColdSignal[2145:457126] signal 正在被创建
//2016-05-23 18:09:51.762 HotColdSignal[2145:457126] 我来第一次订阅signal了--1
 
[signal subscribeNext:^(id x) {
    NSLog(@"我来第二次订阅signal了--%@",x);
}];  
//以上,我们又一次的订阅了signal,发现,signal 被创建了两次,以此类推,我们订阅几次signal, signal就会被创建几次
//2016-05-23 18:17:54.320 HotColdSignal[2155:459009] signal 正在被创建
//2016-05-23 18:17:54.321 HotColdSignal[2155:459009] 我来第一次订阅signal了--1
//2016-05-23 18:17:54.321 HotColdSignal[2155:459009] signal 正在被创建
//2016-05-23 18:17:54.321 HotColdSignal[2155:459009] 我来第二次订阅signal了--1

热信号

热信号是主动的,尽管没有被订阅,但是它会时时推送。
热信号是一对多的,一个信号可以有多个订阅者,共享订阅事件。

RACMulticastConnection *connection = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"signal 正在被创建");
    [subscriber sendNext:@"1"];
    return nil;
}] publish];    
[connection connect];
RACSignal *signal = connection.signal;
// 以上,我们创建了一个signal, 通过publish 方法将它转换为RACMulticastConnection(暂时不需要理解RACMulticastConnection是什么意思),然后通过RACMulticastConnection获取signal,运行代码我们发现,signal被创建了,但是我们并没有订阅signal
//2016-05-23 18:28:35.084 HotColdSignal[2167:461305] signal 正在被创建

修改一下代码

RACMulticastConnection *connection = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
     NSLog(@"signal 正在被创建");
     [[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
         [subscriber sendNext:@"1"];
         [subscriber sendCompleted];
     }];
     return nil;
 }] publish];
 [connection connect];
 RACSignal *signal = connection.signal;
 [signal subscribeNext:^(id x) {
     NSLog(@"我第一次来订阅signal了啊--%@",x);
 }];
 
 [signal subscribeNext:^(id x) {
     NSLog(@"我第二次来订阅signal了啊--%@",x);
 }];
 
// 运行代码我们发现与冷信号不一样的是,signal只被创建了一次
//2016-05-23 18:43:55.924 HotColdSignal[2218:466419] signal 正在被创建
//2016-05-23 18:43:56.985 HotColdSignal[2218:466419] 我第一次来订阅signal了啊--1
//2016-05-23 18:43:56.986 HotColdSignal[2218:466419] 我第二次来订阅signal了啊--1

为什么要区分热信号与冷信号

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        NSLog(@"signal 正在被创建");
       //假如这里是一个网络请求呢?
        NSDictionary *dic = @{
                              @"title1" : @"title1",
                              @"title2" : @"title2",
                              @"title3" : @"title3"
        };
        [subscriber sendNext:dic];
        [subscriber sendCompleted];
        return nil;
    }];  
    RACSignal *title1 = [signal flattenMap:^RACStream *(NSDictionary *dic) {
        if ([[dic valueForKey:@"title1"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:[dic valueForKey:@"title1"]];
        }
        else
        {
            return [RACSignal error:[NSError errorWithDomain:@"获取title1错误" code:404 userInfo:@{
                                                                                                 @"value" :dic
                                                                                              }]];
        }
    }];
   
    RACSignal *title2 = [signal flattenMap:^RACStream *(NSDictionary *dic) {
        if ([[dic valueForKey:@"title2"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:[dic valueForKey:@"title2"]];
        }
        else
        {
            return [RACSignal error:[NSError errorWithDomain:@"获取title2错误" code:404 userInfo:@{
                                                                                               @"value" :dic
                                                                                               }]];
        }
    }];
 
    RACSignal *title3 = [signal flattenMap:^RACStream *(NSDictionary *dic) {
        if ([[dic valueForKey:@"title3"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:[dic valueForKey:@"title3"]];
        }
        else
        {
            return [RACSignal error:[NSError errorWithDomain:@"获取title3错误" code:404 userInfo:@{
                                                                                               @"value" :dic
                                                                                               }]];
        }
    }];
 
    RAC(self.label1, text) = [[title1 catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
    RAC(self.label2, text) = [[title2 catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
    RAC(self.label3, text) = [[title3 catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
 
    [[RACSignal merge:@[title1, title2, title3]] subscribeError:^(NSError *error) {
        NSLog(@"错误信息要集中处理啊~~");
    }];
 
     
//2016-05-24 11:13:57.980 HotColdSignal[537:127936] signal 正在被创建
//2016-05-24 11:13:57.982 HotColdSignal[537:127936] signal 正在被创建
//2016-05-24 11:13:57.983 HotColdSignal[537:127936] signal 正在被创建
//2016-05-24 11:13:57.983 HotColdSignal[537:127936] signal 正在被创建
//2016-05-24 11:13:57.983 HotColdSignal[537:127936] signal 正在被创建
//2016-05-24 11:13:57.983 HotColdSignal[537:127936] signal 正在被创建

查看以上代码:运行一下可以发现signal被创建了6次。
因为我们的数据是在sinal中处理的,你可以把它拿在signal外,避免这样的事发生,但你不能否认,业务中我们会将一个网络请求封装成一个singal, 然后去处理返回的结果。这就造成了一个问题,网络请求发送了六次,在更复杂的业务逻辑中可能会更多,当然对于用户还是服务器而言,我们都不希望频繁的发送网络请求。这就是冷信号的弊端,而这一切都可以将冷信号转换为热信号解决。
这里有一个很重要的结论:任何的信号转换(flapmap, merge 等)即是对原有的信号进行订阅从而产生新的信号。

如何处理冷热信号

结论:

  • RACSubject及其子类是热信号
  • RACSignal排除RACSubject类以外的是冷信号

通过以下方法,将冷信号转换为热信号

- (RACMulticastConnection *)publish;
- (RACMulticastConnection *)multicast:(RACSubject *)subject;
- (RACSignal *)replay;
- (RACSignal *)replayLast;
- (RACSignal *)replayLazily;

参考资料

http://blog.leichunfeng.com/blog/2015/12/25/reactivecocoa-v2-dot-5-yuan-ma-jie-xi-zhi-jia-gou-zong-lan/
http://tech.meituan.com/tag/ReactiveCocoa

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

推荐阅读更多精彩内容