(整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载)

上一章节简要的说明了如何实现的热信号。但是像那么写,貌似不是非常优雅。这一章节我们会把冷热信号转换写的跟ReactiveCocoa一样优雅。

ReactiveCocoa内部是如何实现冷热信号转换的呢?我们来看个例子

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

NSLog(@"replaylazily---sendAction");

[subscriber sendNext:@"replaylazily"];

return nil;

}] replayLazily];

[replayLazilySignal subscribeNext:^(id x) {

NSLog(@"subscribe1----%@",x);

}];

[replayLazilySignal subscribeNext:^(id x) {

NSLog(@"subscribe2----%@",x);

}];

没错,只是在原有信号的基础上,增加了一个replayLazily方法掉用。我们从输出上可以看看,是否转为了热信号。

2015-12-29 13:28:03.588 xxxxxx[40933:6054173] <xxxxxx:(232)> replaylazily---sendAction

2015-12-29 13:28:03.589 xxxxxx[40933:6054173] <xxxxxx:(238)> subscribe1----replaylazily

2015-12-29 13:28:03.589 xxxxxx[40933:6054173] <xxxxxx:(242)> subscribe2----replaylazily


发送只有1次,被订阅了两次。那么我们也朝这个目标出发。

我们这次让一个热信号QHQSubject去订阅最初的冷信号,偷偷的将返回改成这个热信号,偷梁换柱而神不知鬼不觉。

-(QHQSignal *)replayLazily {

QHQMulticastConnection *conn = [[QHQMulticastConnection alloc] initWithSourceSignal:self outSignalSubject:[[QHQSubject alloc] init]];

[conn connectSignal];

return conn.connSignal;

}

这里用到了一个新类,用于做这层转化QHQMulticastConnection,它需要一个源,和一个订阅信号。当执行connectSignal方法后,让热信号订阅最初信号。

-(void)connectSignal {

[_sourceSignal subscribe:_connSignal];

}

让热信号称为接下来流的来源。看似已经天衣无缝了,执行下,看看结果如何

-(void)demoFourReplayLazily {

QHQSignal *replaySignal = [[QHQSignal createSignal:^(id subscriber) {

[subscriber sendNext:@"replaySignal---send"];

}] replayLazily];

[replaySignal subscribeNext:^(id x) {

NSLog(@"sub1 ---- %@",x);

}];

[replaySignal subscribeNext:^(id x) {

NSLog(@"sub2 ---- %@",x);

}];

}

2015-12-29 13:39:59.345 PageText[42204:6070078] replaySignal----send


怎么没有输出订阅的结果呢?确实不应该输出结果,开始分析下原因。当你掉用replayLazily方法时,你已经偷偷摸摸将信号换成了QHQSubject,在这个过程中,你已经订阅了信号,也就是最终的输出结果。让后你再去订阅这个QHQSubject的时候,它做不了任何事情,因为信号的发送已经过去了,过去了,了。我们可以做个延迟发送事件看看。

QHQSignal *replaySignal = [[QHQSignal createSignal:^(id subscriber) {

NSLog(@"replaySignal----send");

[subscriber sendNext:@"replaySignal---send"];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

NSLog(@"Delay-----replaySignal----send");

[subscriber sendNext:@"Delay-----replaySignal---send"];

});

}] replayLazily];

[replaySignal subscribeNext:^(id x) {

NSLog(@"sub1 ---- %@",x);

}];

[replaySignal subscribeNext:^(id x) {

NSLog(@"sub2 ---- %@",x);

}];

发送了两次事件,一次是理解发送,另一次做了延迟。看看结果

2015-12-29 13:45:35.560 PageText[42399:6074028] replaySignal----send

2015-12-29 13:45:37.561 PageText[42399:6074028] Delay-----replaySignal----send

2015-12-29 13:45:37.562 PageText[42399:6074028] sub1 ---- Delay-----replaySignal---send

2015-12-29 13:45:37.562 PageText[42399:6074028] sub2 ---- Delay-----replaySignal---send

延迟发送的事件确实收到了,说明确实转化成了热信号。但是我们总不能每次都延迟一下吧,当然我们可以搞定这个问题,我们让热信号把事件存起来,订阅这订阅后把事件都发送出去。这个时候需要一个可以保存事件的热信号。

因此,我们创建了一个新类继承于QHQSubject

@interface QHQReplaySubject ()

@property (nonatomic, assign) NSUInteger capacity;

@property (nonatomic, strong) NSMutableArray *values;

@end

它会将每次发送来的事件保存在values数组中,如果数组容量大于承载capacity,将会移除掉更早的事件

-(void)sendNext:(id)next {

[_values addObject:next];

[super sendNext:next];

if (_values.count >_capacity) {

[_values removeObjectAtIndex:0];

}

}

它每次被订阅时,都需要首先将已经保存的信号发送给订阅着

-(void)subscribe:(id<QHQSubscrib>)sub {

for (id value in _values) {

[sub sendNext:value];

}

[self.subscribers addObject:sub];

}

这样,第一次的信号就不会丢失。

-(QHQSignal *)replayLazily {

QHQMulticastConnection *conn = [[QHQMulticastConnection alloc] initWithSourceSignal:self outSignalSubject:[QHQReplaySubject replaySubjectWithCapacity:1]];

[conn connectSignal];

return conn.connSignal;

}

简单的将热信号替换成能够保存1个老信号的热信号,那么问题迎刃而解

2015-12-29 14:02:00.766 PageText[43381:6084580] replaySignal----send

2015-12-29 14:02:00.767 PageText[43381:6084580] sub1 ---- replaySignal---send

2015-12-29 14:02:00.767 PageText[43381:6084580] sub2 ---- replaySignal---send

2015-12-29 14:02:02.768 PageText[43381:6084580] Delay-----replaySignal----send

2015-12-29 14:02:02.769 PageText[43381:6084580] sub1 ---- Delay-----replaySignal---send

2015-12-29 14:02:02.770 PageText[43381:6084580] sub2 ---- Delay-----replaySignal---send

输出符合预期

实际上,RAC也是这么做的,不过它将所有的接口都处理成线程安全的。

ReactiveCocoa源码拆分解析(四)的更多相关文章

  1. ReactiveCocoa源码拆分解析(一)

    (整个关于ReactiveCocoa的工程可以在https://github.com/qianhongqiang/QHQReactive下载) ReactiveCocoa的介绍我就不说了,可以自行百度 ...

  2. ReactiveCocoa源码拆分解析(二)

    (整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) 上面抽丝剥茧的把最主要的信号机制给分离开了.但在RA ...

  3. ReactiveCocoa源码拆分解析(七)

    (整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) 在这篇博客中,我将把ReactiveCocoa中的擦 ...

  4. ReactiveCocoa源码拆分解析(六)

    (整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) RAC为了实现优雅的信号绑定,可谓使尽浑身解数,不仅 ...

  5. ReactiveCocoa源码拆分解析(五)

    (整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) 好多天没写东西了,今天继续.主要讲解RAC如何于UI ...

  6. ReactiveCocoa源码拆分解析(三)

    (整个关于ReactiveCocoa的代码工程可以在https://github.com/qianhongqiang/QHQReactive下载) 这一章节主要讨论信号的“冷”与“热” 在RAC的世界 ...

  7. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  8. Spring框架之spring-web web源码完全解析

    Spring框架之spring-web web源码完全解析 spring-web是Spring webMVC的基础,由http.remoting.web三部分组成,核心为web模块.http模块封装了 ...

  9. 【原】AFNetworking源码阅读(四)

    [原]AFNetworking源码阅读(四) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇还遗留了很多问题,包括AFURLSessionManagerTaskDe ...

随机推荐

  1. POJ3250[USACO2006Nov]Bad Hair Day[单调栈]

    Bad Hair Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 17774   Accepted: 6000 Des ...

  2. PS 切图

    1.选择要切哪一块 比如:要切取人物图片, 会自动选择所选的图层 打开关闭某个图层 然后在图层上点击右键,选择合并组 然后Ctrl+c复制--ctrl+n新建画板--

  3. python 环境搭建

    python下载地址: 进入https://www.python.org/download/releases/3.3.4/,下载Windows X86-64 MSI Installer (3.3.4) ...

  4. 微博公众平台(二)-- Token验证代码

    Token,验证逻辑:1.将Token.timestamp.nonce放入数组 2.将数组从小到大排列 3.将数组按顺序拼装成一个字符串 4.对生成的字符串进行SHA1加密 5.将密文转换为小写 6. ...

  5. 20145208《信息安全系统设计基础》实验五 简单嵌入式WEB 服务器实验

    20145208<信息安全系统设计基础>实验五 简单嵌入式WEB 服务器实验 20145208<信息安全系统设计基础>实验五 简单嵌入式WEB 服务器实验

  6. 【腾讯GAD暑期训练营游戏程序班】游戏场景管理作业说明文档

    场景管理作业说明文档                              用了八叉树的算法,测出三层时最快,区域范围内物体数量为21块,控制台打印出的结果如图所示: 场景物体:游戏中,所有具有空 ...

  7. [译]Spring构建微服务

    此文为译文,原文地址 介绍 本文通过一个使用Spring.Spring Boot和Spring Cloud的小例子来说明如何构建微服务系统. 我们可以通过数个微服务组合成一个大型系统. 我们可以想象下 ...

  8. 代码批量生成WORD的遇到的问题及解决

    好久没搞工具了,最近因为处理大规模公文处理单文档,自己写了个批量处理WORD的程序:在调试过程中,主要遇到两个问题 第一个是WORD的模板 数据很多,但是WORD模板只需要一个,将数据替换WORD里标 ...

  9. java高新技术-枚举

    1.什么是枚举 枚举是jdk1.5后才增加的新特性 用枚举就是要规定一个新的类型,那么要用这个类型的值就必须是我规定的那些值.如果不是那些值,编译器就会报错,好处是编译时就会做出判断 2.用普通类模拟 ...

  10. 关于redis的keys命令的性能问题

    KEYS pattern 查找所有符合给定模式 pattern 的 key . KEYS * 匹配数据库中所有 key . KEYS h?llo 匹配 hello , hallo 和 hxllo 等. ...