ReactiveCocoa源码拆分解析(四)

(整个关于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也是这么做的,不过它将所有的接口都处理成线程安全的。

转载于:https://www.cnblogs.com/qianhongqiang/p/5085556.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Emacs编写mybatis

<?xml version"1.0" encoding"utf-8"?> 用Emacs编写mybatis用Emacs编写mybatis Table of Contents 1. 效果图2. 配置1 效果图 2 配置 现在web开发&#xff0c;最流行的orm框架非mybatis莫属了&#xff0c;它功能强大&#xff0c;编写简单灵活&…

lambda显式声明返回值

10.21 编写一个lambda&#xff0c;捕获一个局部int变量&#xff0c;并递减变量值&#xff0c;直至它变为0.一旦变量变为0&#xff0c;再调用lambda应该不再递减变量。lambda应该返回一个bool值&#xff0c;指出捕获的变量是否为0. #include<iostream> #include<algori…

【Codeforces Round #452 (Div. 2) C】 Dividing the numbers

【链接】 我是链接,点我呀:) 【题意】 在这里输入题意 【题解】 n为偶数。 l 1, r n (l,r)放在一组 l,r-- 新的l,r放在另外一组 直到l1r 这个时候,判断两组的和,如果一样的话,分散在两组 差为1否则差为0n为奇数 l 2,r n (l,r)放在一组 l,r-- 新的l,r放在另外一组 直到l1r…

java中reject方法作用_Java BindingResult.rejectValue方法代碼示例

本文整理匯總了Java中org.springframework.validation.BindingResult.rejectValue方法的典型用法代碼示例。如果您正苦於以下問題&#xff1a;Java BindingResult.rejectValue方法的具體用法&#xff1f;Java BindingResult.rejectValue怎麽用&#xff1f;Java BindingResult.r…

java方法参数

Java程序设计语言总是采用值调用。也就是说&#xff0c;方法得到的是所有参数的一个拷贝&#xff0c;特别是方法不能修改传递给它的任何参数变量的内容。 基本类型参数 1&#xff09;X被初始化为percent值的一个拷贝&#xff1b; 2&#xff09;X被乘以3等于30。但是percent仍然…

SaltStack源码分析之:master端执行salt模块大致流程

2019独角兽企业重金招聘Python工程师标准>>> ##JOB执行流程 先看下官网对于master端的工作流程的介绍&#xff1a; The Salt master works by always publishing commands to all connected minions and the minions decide if the command is meant for them by ch…

myecplise新建Maven项目Filter选什么,使用myeclipse建立maven项目

myecplise新建Maven项目Filter选什么 使用myeclipse建立maven项目 1234567分步阅读maven是管理项目的&#xff0c;myeclipse是编写代码的。第一次写项目都要配置好多东西&#xff0c;很麻烦&#xff0c;now 来看看怎样新建一个maven项目。 工具/原料 myeclipsemaven方法/步骤 1…

python参数传递时不构造新数据对象_关于函数的参数传递(parameter passing),以下选项中描述错误的是_学小易找答案...

【单选题】下面代码的输出结果是: a [] for i in range(2,10): count 0 for x in range(2,i-1): if i % x 0: count 1 if count 0: a.append(i) print(a)【单选题】Python3.0正式发布的年份是【单选题】以下选项中,对于函数的定义错误的是【单选题】关于函数的参数传递(pa…

关于TCP/IP与数据传输

一、TCP/IP的具体含义&#xff1a; 从字面意思来讲&#xff0c;很多人会认为TCP/IP是指TCP与IP这两种协议。有时确实也可以说是这两种协议&#xff0c;但是大部分情况下所说的是利用IP进行通信时所必须用到的协议群的统称。具体来说IP,ICMP,TCP,UDP,FTP以及HTTP等都属于TCP/IP协…

geohash php_空间索引-geohash算法实现

算法简介geohash是实现空间索引的一种算法,其他实现空间索引的算法有:R树和其变种GIST树、四叉树、网格索引等算法基本原理geohash算法将地球理解为一个二维平面&#xff0c;将平面递归分解成更小的子块&#xff0c;每个子块在一定经纬度范围内拥有相同的编码&#xff0c;这种方…

ActiveReports 报表控件V12新特性 -- 新增JSON和CSV导出

ActiveReports 报表控件V12新特性 -- 新增JSON和CSV导出 ActiveReports 是一款专注于 .NET 平台的报表控件&#xff0c;全面满足 HTML5 / WinForms / ASP.NET / ASP.NET MVC / WPF 等平台下报表设计和开发工作需求&#xff0c;作为专业的报表工具为全球超过 300,000 开发人员提…

Codeforces Round #112 (Div. 2)---A. Supercentral Point

Supercentral Pointtime limit per test2 secondsmemory limit per test256 megabytesinputstandard inputoutputstandard outputOne day Vasya painted a Cartesian coordinate system on a piece of paper and marked some set of points (x1, y1), (x2, y2), ..., (xn,…

php imap配置,怎么为PHP编译imap扩展?

为PHP编译imap扩展的方法&#xff1a;首先安装“imap-open2007e”&#xff1b;然后下载源代码&#xff1b;接着准备好系统的“imap-open”环境&#xff1b;最后进入“./ext/extension/imap/”文件夹下执行“make”命令即可。怎么为PHP编译imap扩展&#xff1f;最近为项目增加了…

加载指定路径下所有文件

工作中经常遇到加载某个文件夹下的所有文件&#xff0c;然后对文件遍历&#xff0c;今天写代码时遇到一个好的类ArrayDeque&#xff0c;整理一下&#xff0c;做一下笔记 下面写了一个测试类 package com.hpzx.test;import java.io.File; import java.util.ArrayDeque; import j…

每日站立会议个人博客二

事件昨天干了什么优化了商品详细信息界面的多个图片显示方式今天要做什么对商品搜索结果页面进行深度优化&#xff0c;增加搜索筛选功能遇到的问题多图片显示实现过程中&#xff0c;图片的排列方式出现了问题。转载于:https://www.cnblogs.com/mqlblog/p/8063718.html

vmware安装minimal centos报错/etc/rc5.d/s99local : line

2019独角兽企业重金招聘Python工程师标准>>> 有人用vmware安装minimal centos报错/etc/rc5.d/s99local : line:25 : eject : command not found 。我们看下完整报错内容&#xff1a; Installing VMware Tools, please wait...mount: special device /dev/hda does n…

php print div,JavaScrip实现PHP print_r的数功能(三种方法)

方法一function print_r(theObj) {var retStr ;if (typeof theObj object) {retStr ;for (var p in theObj) {if (typeof theObj[p] object) {retStr [p] > typeof(theObj) ;retStr print_r(theObj[p]) ;} else {retStr [p] > theObj[p] ;}}retStr ;}re…

Android源代码下载方法具体解释

作者&#xff1a;张星 相信非常多下载过内核的人都对这个非常熟悉 git clone git://android.git.kernel.org/kernel/common.git kernel 可是这是在曾经&#xff0c;如今假设这么运行的话&#xff0c;会显演示样例如以下内容 Initialized empty Git repository in /home/star/w…

一些概念

1. 分布式锁&#xff1a;考虑利用redis的原子性特性&#xff0c;先确定redis中是否已处理过某个请求。如果没有&#xff0c;就创建&#xff0c;然后执行。执行完&#xff0c;清除redis里面的标记。因为redis是共享的&#xff0c;所以这种方式可以过滤掉重复请求引起的问题。 2.…