网络科技

    今日:240| 主题:245157
收藏本版
互联网、科技极客的综合动态。

[其他] ReactiveCocoa核心元素与信号流

[复制链接]
生死相随 发表于 2016-10-14 15:08:28
429 33

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
概述

   ReactiveCocoa(以下简称“RAC”)是一个函数响应式编程框架,它能让我们脱离Cocoa API的束缚,给我们提供另外一套编码的思路与可能性,它能在宏观层面上提升代码易读性与稳定性,让程序员写出富有“诗意”的代码,因此备受业内推崇。本文略过RAC基本概念与基础使用(有些技术点可以参考美团点评技术博客之前的几篇文章: RACSignal,冷信号与热信号系列,内存泄漏 。),着重介绍RAC数据流方面的内容,剖析RAC核心元素与RAC Operation在数据流中扮演的角色,并从数据流的角度切入,介绍RACComand与RACChannel。
  RAC核心元素与管线

  在绘制UI时,我们常希望能够直接获取所需数据,但大多数情况下,数据需要经过多个步骤处理后才可使用,好比UI使用到的数据是经过流水线加工后最后一端产出的成品。众所周知,流水线是由多个片段管线组成,上端管线处理后的已加工品成为下端管线的待加工品,每段管线都有对应的管线工人来完成加工工作,直至成品完成。RAC则为我们提供了构建数据流水线的能力,通过组合不同的加工管线来导出我们想要的数据。想要构建好RAC的数据流水线,我们需要先了解流水线中的组成元素——RAC管线。RAC管线的运作实质上就是RAC中一个信号被订阅的完整过程。下面我们来分析下RAC中一个完整的订阅过程,并由此来了解RAC中的核心元素。
  RAC核心是Signal,对应的类为RACSignal。它其实是一个信号源,Signal会给它的订阅者(Subscriber)发送一连串的事件,一个Signal可比作流水线中的一段管线,负责决定管线传输什么样的数据。Subscriber是Signal的订阅者,我们将Subscriber比作管线上的工人,它在拿到数据后对其进行加工处理。数据经过加工后要么进入下一条管线继续处理,要么直接被当做成品使用。通过RAC管线这个比方,我们来详细了解下RAC中Signal的完整订阅过程:
  
       
  • 管线的设计-createSingal:  
  [code]RACSignal *pipeline = [RACSignal createSignal:^RACDisposable*(id subscriber) {
    [subscriber sendNext:@(1)];
    [subscriber sendNext:@(2)];
    [subscriber sendNext:@(3)];

    [subscriber sendCompleted]; // (1)

    return[RACDisposable disposableWithBlock:^{ // (2)
        NSLog(@"the pipeline has sent 3 values, and has been stopped");
    }];
}];[/code]  这里RAC通过类簇的方式,使用RACSignal 的createSignal 方法创建了一个RACDynamicSignal对象(RACSignal的子类), 同时传入对应的didSubscribeBlock参数。这个block里,我们定义了该Signal将按何种方式、发送何种信号值。如文中的pipeline signal在顺序发出了 1、 2、 3 三个数据后,发出结束信号 (1),并且安排好信号终止订阅时的收尾工作 (2),这个过程好比是我们预先设计好一段管线,设定好管线启动后按照何种逻辑,传送出何种数据。但管线传送出待加工数据后需要有工人对其进行加工处理,于是RAC引入了Subscriber。
  
       
  • 管线工人 - Subscriber:  
  [code]RACSubscriber *worker = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];[/code]  Subscriber我们一般称之为订阅者,它负责处理Signal传出的数据。Subscriber初始化的时候会传入nextBlock、 errorBlock、completeBlock,正是这三个block用于处理不同类型的数据信号,处理后的数据或者被抛往下一段管线,亦或者被当做成品送给使用方。Subscriber好比是管线上的工人,负责加工管线上传递过来的各种信号值,不过一旦Subscriber接收到error信号或complete信号,Subscriber会通过相关的RACDisposal主动取消这次订阅,停止管线的运作。那么管线有了,管线上的装配工人有了,如何启动管线?
  
       
  • 启动管线 - subscribe:  
  [code]RACDisposable *disposable = [pipeline subscribe:worker][/code]   通过RACDynamicSignal中的subscribe方法,pipeline signal(RACSignal)开始被worker(RACSubscriber)订阅。在subscribe方法中, pipeline会在执行createSignal时传入didSubscribeBlock,执行的过程遵循之前关于管线的设定,worker将接受到3个数据值与一个complete信号,并使用subscriber中的nextBlock与completeBlock对信号值分别进行处理。管线启动后,会返回一个RACDisposable对象。外部可以通过[RACDisposable dispose]方法随时停止这段管线的工作。一旦管线停止,subscriber worker将不再处理管线传送过来的任何类型的数据。详细的剖析可以参看 http://tech.meituan.com/RACSignalSubscription.html。
  以上三个步骤构成了一个普通信号的订阅流程。但往往在使用RAC时,我们看不到后两者,这是因为RAC将Subscriber的初始化以及[signal subscribe: subscriber]统一封装到[signal subscribeNext: error: completed:]方法中了,如下图所示。这种封装成功屏蔽掉了Subscriber这个概念,进一步简化信号的订阅逻辑,使其更加便于使用。(PS:流水线worker永远都在默默付出!!)
   
ReactiveCocoa核心元素与信号流-1 (稳定性,程序员,可能性,流水线,数据流)

  可以发现,按照上面的订阅流程,信号只有被订阅时才会送出信号值,这种信号我们称之为冷信号(cold signal)。既然有冷信号的概念,就肯定有与之对应的热信号(hot signal)。冷信号好比只有给管线分配工人后,管线才会开启。而热信号就是在管线创建之后,不管是否有配套的工人,管线都会开始运作,可以随时根据外部条件送出数据。送出数据时,如果管线上有工人,数据被工人加工处理,如果没有工人,数据将被抛弃。以下我们仍然从信号的订阅步骤对比冷热信号:(热信号对应的类RACSubject)
  
       
  •   创建信号。与冷信号不同,RACSubject在被创建后将维护一个订阅者数组(subscribers),用于随时存储加入进来的Subscriber。此外不同于RACDynamicSignal,RACSubject在创建时并不去设定要输出的数据,而是通过实现          协议,允许外部直接使用[RACSubject sendNext:]随时输出数据。     
       
  • 创建订阅者。该创建过程与冷信号完全相同,即提前准备好Subscriber对应的nextBlock、errorBlock、completedBlock。
      
  [code]RACSubscriber *worker = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];[/code]  
       
  • 订阅。RACSubject(hotSignal)与RACDynamicSignal(coldSignal)内部都有继承于父类RACSignal的subscribe方法,但实现过程却完全不同。RACDynamicSignal的subscribe会去执行createSignal时准备好的didSubscribeBlock,同时将subscriber传给didSubscribeBlock,让subscriber按照设定好的方式处理相应的数据值。 而热信号RACSubject仅仅只是将subscriber加入到订阅者数组中,其它啥事不干。
       
  •   热信号没有提前规划订阅时信号的输出,因而它需要由外部来控制信号何时输出何种数据值,于是RACSubject实现了          协议,向外提供了[RACSubject sendNext:]、[RACSubject sendError:]、[RACSubject sendComplete:]方法。以sendNext举例,每当使用 [RACSubject sendNext] 时,RACSubject就会遍历一遍自己的subscribers数组,并调用各数组元素(subscriber)准备好的sendNextBlock (1)。     
      
  [code]- (void)sendNext:(id)value
{
    [self enumerateSubscribersUsingBlock:^(id subscriber) {
        [subscriber sendNext:value]; // (1)
    }];
}[/code]   以上是冷、热信号在执行层面上的异同。有时为了消灭副作用或着其它某种原因,我们需要将冷信号转成热信号,让它具备热信号的特性。 这时候我们可以用到[RACDynamicSignal multicast: RACSubject] ,这个方法究其原理也是利用到了RACSubject可随时sendNext的这一特性。具体冷热信号的转换可参见: http://tech.meituan.com/talk-about-reactivecocoas-cold-signal-and-hot-signal-part-3.html 。此外,RACSubject有个子类RACReplaySubject。相较于RACSubject,RACReplaySubject能够将之前信号发出的数据使用valuesReceived数组保存起来, 当信号被下一个Subscriber订阅时,它能够将之前保存的数据值按顺序传送给新的Subscriber。
  这一节大概介绍了RACDynamicSignal、 RACSubject、 RACSubscriber、 RACDisposal在订阅过程中扮演的角色, 事实上调度器RACSchedule也是RAC中非常重要的基础元素。RAC对它的定义是"schedule: control when and where the work the product",它对GCD做了一层很薄的包装。它能够:1.让RACSignal送出的信号值在线程中华丽地穿梭;2.延迟或周期执行block中的内容; 3.可以添加同步、异步任务,同时能够灵活取消异步添加的未执行任务。RACSchedule的使用会在下文提到。
  RAC信号流

  RAC流水线由多段管线组合而成,上节介绍了单条RAC管线的运作,这一节主要介绍:1.RAC管线间的衔接 — RAC Operation;2.RAC信号流的构建。
     RAC Operation 作为信号值的中转站,它会返回一个新信号N。如下图所示,RAC Operation对原信号O传出的值进行加工,并将处理好的数值作为新信号N的输出,这个过程好比将原管线数据加工后抛往一段新的管线,一条RAC流水线就是由各种各样的RAC Operation组合而成的。RAC 提供了许多RACSignal Operation方便我们使用 ,其中[RACSignal bind:]操作是信号变换的核心。因此在剖析RAC Operation的时候,我们主要针对bind以及其衍生出来的flattenMap、 map、flatten进行介绍。随后将RAC流水线应用于一个具体业务需求,详细了解整段RAC信号流的构建。

ReactiveCocoa核心元素与信号流-2 (稳定性,程序员,可能性,流水线,数据流)
    首先我们来解读bind极其衍生出来的几个Operation:
     (1) bind函数会返回一个新的信号N。整体思路是对原信号O进行订阅,每当信号O产生一个值就将其转变成一个中间信号M,并马上订阅M, 之后将信号M的输出作为新信号N的输出。管线图如下:
友荐云推荐




上一篇:赵薇套现11亿:明星IP是被资本催肥的吗?
下一篇:人民币贬值了,现在买 iPhone7 比双十一是个更加不错的选择? ...
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

李孟春 发表于 2016-10-14 17:14:21
星期五过得很不爽!
回复 支持 反对

使用道具 举报

很绝美很感慨 发表于 2016-10-14 17:14:56
看了这么多帖子,第一次看到这么经典的!
回复 支持 反对

使用道具 举报

哈士奇的帅气 发表于 2016-10-14 17:25:58
为保住菊花,这个一定得回复!
回复 支持 反对

使用道具 举报

明少g 发表于 2016-10-14 17:25:59
天空飘过五个字,那都不是事。
回复 支持 反对

使用道具 举报

rt春业逢o 发表于 2016-10-14 18:00:26
不错 支持下
回复 支持 反对

使用道具 举报

夜蓉 发表于 2016-10-15 04:52:52
连广告也信,读书读傻了吧
回复 支持 反对

使用道具 举报

tobe3213 发表于 2016-10-15 23:07:03
神马时候我才能升级咧
回复 支持 反对

使用道具 举报

金明赌神 发表于 2016-10-16 04:28:29
传说中的沙发???哇卡卡
回复 支持 反对

使用道具 举报

196pa 发表于 2016-10-18 12:45:15
简约时尚国际范
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表