ReactiveCocoa框架菜鸟入门(三)——信号(Signal)与订阅者

上一篇文章已经简单的介绍了ReactiveCocoa框架的思想和优势。本文初步研究一下ReactiveCocoa框架的使用方法。

写在开始前

传统的编程思想,大概是用户产生某个事件,然后得到相应的参数,传入事先已经实现的方法中,处理完成后把结果在UI界面上反馈出来。ReactiveCocoa框架中大量的使用了block,这意味着,很多block内的代码,是在将来某一个合适的时刻被执行的。如果你看到block里某个参数并没有被赋值,也没有传入参数,不要奇怪,程序运行到这里的时候还不会执行这个block,至于等到需要执行block的时候,会有参数传入的。这是新手在使用block时非常容易产生的误区,如果没有理解这一点,在看代码的时候会产生相当大的麻烦。

信号(Singal)

ReactiveCocoa最基本也是最关键的一个概念叫做信号(Signal)。官方给出的文档中对于信号如此定义:

[RACSignal] is a push-driven stream with a focus on asynchronous event 
delivery through subscriptions.

当然这个解释是非常抽象的,一会儿再谈。 
个人感觉,linyawen的博客中对信号的解释非常生动形象

信号是数据流,可以被绑定和传递。可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。

请牢牢记住“信号就像一个水龙头”这个概念。它允许各种各样的数据从它这里流过。一个信号可以捕捉当前和未来的值。

订阅者/接收者(Subscriber)

回到最初的官方给出的signal的定义,push-driven stream表示,signal是一个由推动力驱动的数据流。即产生一个数据就push一次并进行一系列处理。反过来说,pull-driven表示处理完一个数据才会要求产生一个数据。

对于一个signal来说,刚刚创建的时候,它还是一个冷信号(Cold signal),只有在有了订阅者(Subscriber)之后,才会变为热信号(Hot signal)。订阅者就好比水龙头最下方的水盆,只有放好了水盆,水龙头才能打开。不然,水(value)不都浪费了么?

如果目前对于信号和订阅者还不了解,这是正常情况。接下来通过代码一起了解他们的工作机制。

初窥ReactiveCocoa

ReactiveCocoa的框架的安装已经在前文谈过,这里不再细讲。具体操作方法参见这里

创建一个空白的工程,从storyboard里面拖入一个UITextField,不妨命名为searchText。 
在viewDidLoad方法里面添加以下代码:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">[<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.searchText</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.rac_textSignal</span> subscribeNext: ^(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> text){
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@"</span>, text);
    }];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

运行一下程序,在textfield中输入“hello”。输出结果应该是这样的

<code class="hljs css has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-05-28</span> 14<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:55</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:57</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.785</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">TwitterInstant</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[716:114961]</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">h</span>
2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-05-28</span> 14<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:55</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:58</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.135</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">TwitterInstant</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[716:114961]</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">he</span>
2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-05-28</span> 14<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:55</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:58</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.303</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">TwitterInstant</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[716:114961]</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">hel</span>
2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-05-28</span> 14<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:55</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:58</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.415</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">TwitterInstant</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[716:114961]</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">hell</span>
2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-05-28</span> 14<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:55</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:58</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.663</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">TwitterInstant</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[716:114961]</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">hello</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

可以发现,每一次textfield中文字发生变化,都执行了block中的代码。 
一切脱离原理讲效果的行为都是耍流氓。相信任何第一次接触这个框架的读者看到这里一定是一头雾水。很可能你会问这些问题:

  1. 为什么参数text就是textfield中的内容而不是其他的任何信息?
  2. 为什么每次textfield中内容发生变化,block都被执行?
  3. subscribeNext方法是什么意思?
  4. 前文所说的信号、订阅者具体指什么?

下面就是时候看看具体的原理了。千万不要着急学习更多的知识,有时候打好基础,彻底理解一个框架的原理对以后的深入学习更有帮助。请记住这四个问题,如果你能不假思索的回答出来,那么就可以开始进一步的学习了。

ReactiveCocoa的基本工作原理

不妨把上述代码自己敲一遍。searchText后面输入.r的时候已经会出现Xcode的智能提示了。这里写图片描述
这里的rac_textSignal就是一个信号。执行了subscribeNext方法后,这个信号被订阅(水龙头下面摆好水盆了)。每当有新的数据(textfiled中内容)出现,信号就捕捉到这个值。把这个值传入block中,并且执行block里的代码,于是就打印出了我们看到的数据。为了搞懂为什么新数据出现时,block被调用,我们需要看看subscribeNext方法的具体实现。

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">- (RACDisposable *)subscribe:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span><RACSubscriber>)subscriber {
    NSCAssert(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NO</span>, @<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"This method must be overridden by subclasses"</span>);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>;
}

- (RACDisposable *)subscribeNext:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (^)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> x))nextBlock {
    NSCParameterAssert(nextBlock != <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);

    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span> completed:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>];
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> subscribe:o];
}

- (RACDisposable *)subscribeNext:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (^)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> x))nextBlock completed:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (^)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>))completedBlock {
    NSCParameterAssert(nextBlock != <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);
    NSCParameterAssert(completedBlock != <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span>);

    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">NULL</span> completed:completedBlock];
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> subscribe:o];
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>

这里从源代码中简单的节选了几个方法的实现。不难发现,subscribeNext是一个方法簇,除了不带block的那个方法(第一个方法)之外,每一个方法中都创建了一个RACSubscriber(订阅者)对象。subscribeNext方法返回一个RACDisposable(销毁者)对象,这个对象可以用来销毁一个信号,大部分时候没有必要这么做。因为没有被持有的信号会被自动释放。

看到这里,有一个问题的答案已经很明显了:谁是订阅者(subscriber)? 
很显然,我们不可能像找到signal那样说rac_textSignal就是一个信号对象,但是订阅者对象就藏在subscribeNext方法中。任何简化的不完全的subscribeNext方法都可以拓展成一个完整的subscribeNext方法:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.searchText</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.rac_textSignal</span> subscribeNext:^(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> x) {
        <<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#code#></span>
    } error:^(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSError</span> *error) {
        <<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#code#></span>
    } completed:^{
        <<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#code#></span>
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

而这里我们指定的三个block将会被用来构建一个订阅者(subscriber)。

信号(Signal)和订阅者(Subscriber)

还记得第一个demo的四个问题么?回想一下,是不是已经解决问题三和四了呢?为了弄明白前两个问题,我们来看一看信号的工作原理。rac_textSignal是一个已经被创建好的信号,为了不是一般性,我们自己创建一个信号:使用createSignal方法。

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">- (RACSignal *)createSignal{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [RACSignal createSignal:^RACDisposable *(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span><RACSubscriber> subscriber) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"signal created"</span>);
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>;
    }];
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

有了这个方法,我们就可以创建一个最简单的自定义的信号了。在viewDidLoad方法中加入这样一行代码:

<code class="hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">RACSignal *signal </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> [self createSignal];</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

运行程序看一看效果吧。并没有什么卵用。。。。。。。这是必然的。说得形象一点,我们搞出来一个水龙头,但是下面还没有放上盆子。说得专业一点,这还是一个冷信号(Cold signal)。还没有被订阅(Subscribe)。归根结底,我们不了解这个createSignal方法的实现原理。 
Ok,按住command键点击方法名,跳过去看看createSignal到底是个啥玩意儿。

<code class="hljs markdown has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-bullet" style="box-sizing: border-box;">+ </span>(RACSignal <span class="hljs-emphasis" style="box-sizing: border-box;">*)createSignal:(RACDisposable *</span> (^)(id<span class="xml" style="box-sizing: border-box;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">RACSubscriber</span>></span></span> subscriber))didSubscribe {
<span class="hljs-code" style="box-sizing: border-box;">    return [RACDynamicSignal createSignal:didSubscribe];</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

这个方法有一个block。block需要一个RACSubscriber(订阅者)对象作为传入的参数,会传出一个销毁者(RACDisposable)对象。block名叫做didSubscribe,显然这个block会在block被subscribe之后触发。现在明白冷信号是什么意思了么?没有订阅者(Subscriber)的时候,用于创建signal的block都没有被执行,这个信号当然没有任何卵用。

在viewDidLoad方法中再加一行代码呢:

<code class="hljs ini has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 102, 102);">[signal subscribeNext:^(id x) {
        ;
    }]</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

即使只是一个空的block,但是因为signal现在被订阅(Subscribe)了,之前的名为didSubscribe的block就被执行了。此时会输出

<code class="hljs css has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">2015<span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">-05-28</span> 15<span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:36</span><span class="hljs-pseudo" style="color: rgb(0, 0, 0); box-sizing: border-box;">:42</span><span class="hljs-class" style="box-sizing: border-box; color: rgb(155, 112, 63);">.661</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">TwitterInstant</span><span class="hljs-attr_selector" style="color: rgb(0, 136, 0); box-sizing: border-box;">[823:253903]</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">signal</span> <span class="hljs-tag" style="color: rgb(0, 0, 0); box-sizing: border-box;">created</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

修改一下刚刚的代码,增加一个NSLog的功能。修改后的subscribeNext方法应该像这样:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">RACSignal *signal = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span> createSignal];
    [signal subscribeNext:^(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span> x) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"aaa"</span>);
    }];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

运行程序。Oh,Shit!依然没有任何卵用。说好的会执行subscribeNext的block内的代码呢?aaa怎么没有打出来? 
其实,仔细一想,这样的结果反而是合理的。我们之前讨论的信号(Signal)被订阅(Subscribe)之后,信号这个水龙头的阀门被打开,水流过信号,落入盆子里。可是为啥落入盆子里就会调用subscribeNext的block中的代码?文章的最初写了,block只是一段预先定义好的代码,在将来的某个时间被调用。可我们至今没有在任何代码中看到这样的调用。我们还是再好好看一看订阅者(Subscriber)吧。

细说订阅者(Subscriber)

之前我们简单的看了订阅者(Subscriber)对象的工作原理:在subscribeNext方法中我们创建了一个订阅者(Subscriber)对象。这个对象是怎么被创建的呢?关键在于那个出现了无数次的subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed方法:

<code class="hljs applescript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">+ (instancetype)subscriberWithNext:(void (^)(<span class="hljs-property" style="box-sizing: border-box;">id</span> x))next <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span>:(void (^)(NSError *<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span>))<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span> completed:(void (^)(void))completed {
    RACSubscriber *subscriber = [[self alloc] init];

    subscriber->_next = [next <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">copy</span>];
    subscriber->_error = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">error</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">copy</span>];
    subscriber->_completed = [completed <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">copy</span>];
<span class="hljs-command" style="box-sizing: border-box;">
    return</span> subscriber;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

看到这里,我想已经非常清楚了。订阅者(Subscriber)对象持有三个属性,都是block。在订阅者的创建过程中,对这三个进行了赋值。等待在将来的某一刻被调用。这就好比这个盆子(订阅者)有许多功能,对于不同的滴水状态,具备不同的处理方法。

同时订阅者(Subscriber)对象还对外提供了三个方法的调用接口:

<code class="hljs erlang has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-pp" style="box-sizing: border-box;">- <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(void)</span>sendNext:<span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(id)</span>value;
- <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(void)</span>sendError:<span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(<span class="hljs-variable" style="box-sizing: border-box;">NSError</span> *)</span>error;
- <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(void)</span>sendCompleted;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

以- (void)sendNext:(id)value方法为例看一看它的实现:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span>)sendNext:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)value {
    @synchronized (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span>) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> (^nextBlock)(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>) = [<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">self</span><span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">.next</span> copy];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (nextBlock == <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;

        nextBlock(value);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

其实最核心的功能即时调用了自己的nextBlock并传入相应的参数而已。

那么订阅者(Subscriber)对象的这三个方法什么时候被调用呢?又应该调用哪一个呢?答案是:由信号决定。试想一下:水龙头告诉底下的盆子:“我要滴水了,你存一下吧。”。这就是让订阅者(盆子)执行nextBlcok。如果水龙头说:“我滴完水了,你可以歇一会了。”这就是让订阅者(盆子)执行completeBlock。如果水龙头说:“我滴不了水了,坏掉了,你可以歇一会了。”这就是让订阅者(盆子)执行errorBlock。显然,在一个信号(Signal)的生命周期中,可以发送无数次next事件,和唯一一次complete或者error事件。

改造一下最初创造signal的方法:

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">- (RACSignal *)createSignal{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [RACSignal createSignal:^RACDisposable *(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span><RACSubscriber> subscriber) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"signal created"</span>);
        [subscriber sendNext:<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>];
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">nil</span>;
    }];
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

再次运行,就会发现aaa已经被打印出来了。关键就在于这一次我们调用了订阅者(Subscriber)的sendNext方法。

说了这么多,回头看看问题一。重点在于这个rac_textSignal。如果有兴趣可以看看它的实现。其实本质上还是监听了textfield的text属性。当它发生变化时,就把它的值传出来。至于为什么每次传出的都是text值,这是由这个signal的创建方法决定的。

至于问题二,我们执行了subscribeNext方法创建了一个订阅者(Subscriber),这个订阅者的nextBlcok方法已经被赋值。而rac_textSignal这个信号的实现中,在每次text发生变化的时候,就会调用订阅者的sendNext方法,从而调用nextBlcok中的代码。

这就是一个信号(Signal)与订阅者(Subscriber)的简单实用。当然,ReactiveCocoa框架的功能远不止这些。下一章,我们来讨论一下更多的关于信号(Signal)的使用方法——《ReactiveCocoa框架菜鸟入门——信号(Signal)详解》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值