ReactiveCocoa-Swift部分入门指南-SignalProducer

原文地址: 传送门简书只做同步更新功能


学习过ReactiCocoa(以下简称RAC)的同学一般都会使用Objective-C的部分,不过RAC3之后支持了Swift,目前RAC3.x支持的是Swift1.x系列,RAC4支持的是Swift2.x系列。今天花了一点时间学习了下Swift部分示例代码。这里做些记录。Swift是支持playground,可以使用Markdown编写文档,并且所见即所得的界面方便学习。更可以插入图片。方便阅读。

学习知识必备

默认你已经学过RAC-OC部分, Swift语言,并对Monad,functional Programming有些简单的了解,或者,如果你学习了RXSwift更好。

Start

PlaygroundUtility

先来观察一下这个里面有两个方法

scopedExample 方便测试,并分割日志输出,Error也是为了测试方便。

SignalProducer

一个信号发生器,是SignalProducer类型的实例,它可以创建信号(signals)并施加附作用(side effects)。

信号发生器用来表示操作或者任务,比如网络请求,每一次对它调用start()将会生成一个新的潜在操作,并允许调用者观察它的结果。还有一个startWithSignal()方法,会给出产生的信号,允许在必要的情况下被监听多次。

根据start()方法的动作方式,被同一个信号发生器生成的信号可能会有不同的事件顺序或版本,甚至事件流完全不一样!和普通的信号不同,在观察者连接上之前,信号发生器不会开始工作(也就没有事件会生成),并且在每一个新的监听器连接上时其工作都会重新开始一个单独的工作流

启动一个信号发生器会返回一个销毁器(disposable,我也不知道怎么翻译合适),它可用来打断或取消被生成信号的工作。

和信号一样,信号生成器可以通过map、filter等原函数操作。使用lift方法,所有信号的原函数可以被提升成为以信号生成器为对象的操作。除此以外,还有一些用来控制何时与如何启动信号生成器的原函数,比如times。

补充,这段我是参考自ReactiveCocoa 4 图解之六——信号发生器(SignalProducer),不过我觉得说的相当之晦涩,在学习这部份的时候,我已经学习了,RAC-OC部分,RXSwift,冷热信号等概念。突然出了一个SignalProducer的概念会让读者很难理解,其实很容易就发现,SignalProducer会带来附作用(冷信号),Signal不会带来副作用(热信号),那他们就很好理解了,SignalProducer类似RACOC中的RACDynamicSignal,Signal类似RACSubject。
通过lift函数可以让热信号转变为冷信号。
如果想学习Signal部分参考文章底部链接

Subscription

一个信号生成器代表了一种可以在需要的时候才被启动的操作(不像Signal是自启动的),这种信号是冷信号,在刚开始这个信号的状态也为冷(未激活), 既然是冷信号,那么就意味这一个观察者不会错过任何被信号生成器发出的值。

补充: 像signal 是创建的时候状态为cold(理解为未激活) ,被订阅时状态为hot (理解为激活)。
但是冷信号和热信号与状态为冷热是两个不同的概念。冷信号会带来附作用,热信号不会
这里我把副作用(side effect) 理解为附作用,有时候这是一个很必要的附加操作,并不一定都是无益的,不然就没有存在的价值了。
如果读者觉得理解的不对,请指出后续会继续修改。

像不像是RACDynamicSignal的创建方式,这不过不同与Sinal的是 这里的发送信号的观察者是在内部通过 Signal.pipe() 生成的,不需要外部创建。
SignalProduce是冷信号,任何一个订阅者/观察者都不会错过任何事件
start方法类似与Signal的 signal.observe()方法,只不过Signal的方法只有一个作用,就是关联一个观察者,而SignalProduce的start方法还多了一个激活信号的功能。

Empty

一个会立即调用complete事件的信号生成器

Signal调用的是interrup方法,暂时不知道为什么,可能是为了区分语义把。Signal是有时序的,SignalProduce是没有时序的。使用中断更合适吧。

Never

一个什么都不会发送的信号生成器

buffer

创建一个事件队列可以回放已经发送的事件。

当一个值被发送的时候,它会被放进缓冲区内,如果缓冲区已经溢出,就会丢弃旧的值,
这些被缓存的值将会被保留,直到这个信号被终结。当一个信号启动的时候,如果队列里没有任何值,所有被发送的新值都会被自动转发到观察者哪里,知道观察者收到一个终止事件。

当一个终止事件被发送到队列中,观察者不会再收到任何值,并且这个事件不会被计算buffer的缓冲区大小,所以没有缓存的值都会被丢弃。

Buffer更像RACReplaySubject,所以Buffer应该也算一个热信号

startWithSignal

通过Producer返回一个Signal,当闭包调用时返会signal开始发送事件。
闭包返回一个Disposable 可以用来中断Signal或者完成。

startWithNext

通过信号生成器创建一个信号,并且给这个信号内部直接构建一个观察者,在指定的闭包中会直接订阅next事件。

返回一个Disposable,可以中断这个信号。中断之后这个闭包不会再被调用

其实类似与OC部分的[subscribeNext: ^(id value){}],观察者不用自己构建了

注意: 这个订阅只能接受next事件

startWithCompleted

同startWithNext, 只不过只能接受complete事件

startWithFailed

同startWithNext, 只不过只能接受Failer事件事件

startWithInterrupted

同startWithNext, 只不过只能接受interrupted事件事件

operators

lift

这个相对难理解点。大致类似与RAC-OC部分中的bind函数,monad中的bind函数

可以理解为所有的原函数都是通过lift去实现的,接用中间信号来实现一系列的信号变换

map

把每个值都转换为新的值

mapError

把收到的error转换为新的error

filter

过滤不符合条件的值

take

take(num) 只取前几次的值

observeOn

在指定的调度器上分发事件

collect

在发送完成的时候将一系列的值聚合为一个数组

collect(count:)

在发送数据的时候(不需要发送complete)的时候将一系列的值聚合为数组,数组的长度为count,如果又很多数据,将会返回多个数组

collect(predicate:) matching values inclusively

通过谓词将一系列的值聚合为一个数组,注意在发送complete时候,如果前面只剩下一个值,就不需要聚合,(因为没有其他元素和最后一个元素聚合),直接返回一个只有一个元素的数组。 如果没有数据则返回一个空数组。

  1. 尝试把所有数据打开,看看什么结果,
  2. 尝试只注释4看什么结果

collect(predicate:) matching values exclusively

和上一个不同的是,如果谓词成功就把之前的聚合在一起。 可以理解为把成功的界限当作分隔符

combineLatestWith

将第一个信号生成器的values 和被聚合信号生成器的最后一个值聚合为一个元组

新产生的信号生成器不会发送任何值,只是转发,任何一个原来的信号被中断,这个新的信号生成器也会中断

skip

skip(num), 跳过num此发送的事件

materialize

将被发送的值(value)变成Event, 允许他们被修改。换句话说把一个值变成一个Monad (在前文中写到Event就是一个monad)

当收到一个compelet或者Failure事件,这个新的信号生成器,会发送事件并且结束。当收到一个interruped事件,这个新的信号生成器也会中断

sampleOn

  1. 当Sampler(被操作的信号生成器)发送任何事件的时候,都转发原来信号生成器的最后一个值
  2. 如果当一个sampler (被操作的信号生成器)启动是,当前的值没有被观察者,没有任何事情发生
  3. 新产生的信号生成器从源信号生成器哪里发送数据,如果两个信号生成器任何一个complete或者interrupt 新产生的都会中断

combinePrevious

向前合并,每发送一个值就结合历史发送数据的最后一个构造成一个新的元组返回。在第一个发送时由于没有历史数据,所以combinePrevioud传递了一个默认值。当作第一次的合并

scan

类似reduce,将值聚合为一个新的值,每次聚合都保留结果作为下次的默认值。首次需给出默认值。

每次聚合都会发送这个值

reduce

和scan类似 ,区别为reduce只发送聚合后的值并且立即结束

skipRepeats

跳过表达式里返回true的值,第一个值不会被跳过

skipWhile

对每个值都去做判断,直到返回faslse,之前的值会被跳过

takeUntilReplacement

在被替换的信号发生器发送信号之后,发送被替换的信号。

takeLast

在发送complete事件后支取count此数据

ignoreNil

如果发送的事件是可选类型,解包这些可选类型,并且丢弃nil值

zipWith

压缩信号生成器,只有在两个信号都有数据发送之后,新的信号生成器才会发送数据。
新的数据被组合为元组。

times

time(count) 重复发送count数据,每次重复必须上次发送完成事件

retry

如果收到失败事件重试retry(count)次

then

当第一个信号发送complete时,第二个信号被替换到信号发送线路上,如果有任何失败事件,后面的就替换失败。

第一个信号发送的所有事件都会被忽略
这个没有使用场景比较难理解。看图

then

replayLazily

创建一个新的SignaProduce,内部包含了一个生产者去组播的发送事件。直到capacity(可以保留的数量)。这意味者所有的观者者看到是相同版本的值或者错误。

类似RAC-OC部分中的replayLazily ,底层生产者是懒加载的。第一次被观察的时候才会启动。在启动时所有的被缓存的值将会被直接发送。
如果你发现你需要实时的值,建议你使用Signal(热信号)代替,这个信号默认会缓存一些值,在某些时候这些缓存值无用。
使用方法类似SignalProducer.buffer(count)
这时候冷信号变成了热信号

补充: OC部分中的replay是直接启动的,replayLazily是懒加载的,Swift部分没有直接启动的

flatMap(.Latest)

将收到的每个事件 都映射为新的Producer,然后摊平,如果原来的producer发送失败,新产生也的立即失败。

flatMapError

把收到的failure事件映射为新的Producer,并且摊平它

sampleWith

在sampler发送nextEvents对源Producer的最后一次值组合形成一个新的元组,如果sample发送的时候,源Producer没有任何事件,则什么都不发生。

一旦源Producer和Sampler都任何一个发送了complete或者interruperd事件,则新产生的Producer理解结束。

logEvents

把所有收到的事件都输出一份日志。


Reference

  1. ReactiveCocoa 4 图解之六——信号发生器(SignalProducer)
  2. ReactiveCocoa-Swift部分入门指南-Signal

 

1 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部