文档地址:Basic Operators
本文将介绍:combineLatest、zip、flatten( .Merge, .Concat, .Latest)、flatMapError、retry、mapError、promoteErrors 操作符。
我翻译的RAC4的文档
ReactiveCocoa 4 官方文档翻译
ReactiveCocoa 4 文档翻译:基本操作符(一)
ReactiveCocoa 4 文档翻译:基本操作符(二)
ReactiveCocoa 4 文档翻译:框架组成介绍
ReactiveCocoa 4 文档翻译:兼容Objective-C
ReactiveCocoa 4 文档翻译--设计指南(一):事件的规范
ReactiveCocoa 4 文档翻译:设计指南(二):信号的规范
[翻译]ReactiveCocoa 4 最佳实践
组合事件流
下面的操作符将多个事件流的值组合成一个统一的新的事件流。
按照最新的值组合
<code> combineLatest </code>函数可以把几个事件流最新的值组合成一个新的事件流。
合成后的新事件流只有在收到每个合成流的至少一个值后才会发送出去。接着就会把每个流的最新的值一起输出。
<pre><code>
let (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe()
let (lettersSignal, lettersObserver) = Signal<String, NoError>.pipe()
let signal = combineLatest(numbersSignal, lettersSignal)
signal.observeNext { next in print("Next: (next)")}
signal.observeCompleted { print("Completed") }
numbersObserver.sendNext(0) // nothing printed
numbersObserver.sendNext(1) // nothing printed
lettersObserver.sendNext("A") // prints (1, A)
numbersObserver.sendNext(2) // prints (2, A)
numbersObserver.sendCompleted() // nothing printed
lettersObserver.sendNext("B") // prints (2, B)
lettersObserver.sendNext("C") // prints (2, C)
lettersObserver.sendCompleted() // prints "Completed"
</code></pre>
<code> combineLatestWith </code>操作符也是同样的工作模式。
可以看出在都收到两个事件流的值,1和A后,开始输出(1,A)。接着每有一个值输入,就根据两个流最近输入的值输出值。
Zipping(拉链)
<code> zip </code>将两个(或者多个)事件流的值成对组合。就像拉链一样。将每个事件流的值按照索引顺序组合输出。意味着如果是一个流的第N个元素,一定要等到另外一个流第N值也收到才会一起组合发出。
<pre><code>
let (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe()
let (lettersSignal, lettersObserver) = Signal<String, NoError>.pipe()
let signal = zip(numbersSignal, lettersSignal)
signal.observeNext { next in print("Next: (next)") }
signal.observeCompleted { print("Completed") }
numbersObserver.sendNext(0) // nothing printed
numbersObserver.sendNext(1) // nothing printed
lettersObserver.sendNext("A") // prints (0, A)numbersObserver.sendNext(2) // nothing printed
numbersObserver.sendCompleted() // nothing printed
lettersObserver.sendNext("B") // prints (1, B)
lettersObserver.sendNext("C") // prints (2, C) & "Completed"
</code></pre><code> zipWith </code>操作符也是同样的工作模式。
图示中,前面4个值都会组合输出。注意第一个流的5,因为第二个事件流没有第5个值还没有收到,所以没有发出。
压平信号产生源(Flattening producers)
<code> flatten </code> 将一个事件流里的事件流变成一个单一的事件流。新的事件流的值按照指定的策略(FlattenStrategy)由内部的事件流的值组成。
被压平的值按照会变成外层的流的类型。比如:一个SignalProducers里的Signal,被flatten后的类型是SignalProducers。
想象下面values里面的三组值的发出时间根据图里的位置排列。
简单的说就是merge按照时间顺序组成,concat则是按照里面整个流顺序组合。latest是只记录最近一次过来的值的那个流。
合并
<code> .Merge </code> 策略将每个流的值立刻组合输出。无论内部还是外层的流如果收到失败就终止。
<pre><code>
let (producerA, lettersObserver) = SignalProducer<String, NoError>.buffer(5)
let (producerB, numbersObserver) = SignalProducer<String, NoError>.buffer(5)
let (signal, observer) = SignalProducer<SignalProducer<String, NoError>, NoError>.buffer(5)
signal.flatten(.Merge).startWithNext { next in print(next) }
observer.sendNext(producerA)
observer.sendNext(producerB)
observer.sendCompleted()
lettersObserver.sendNext("a") // prints "a"
numbersObserver.sendNext("1") // prints "1"
lettersObserver.sendNext("b") // prints "b"
numbersObserver.sendNext("2") // prints "2"
lettersObserver.sendNext("c") // prints "c"
numbersObserver.sendNext("3") // prints "3"
</code></pre>
示意图:
连接
<code> .Concat </code> 策略是将内部的SignalProducer排序。外层的producer是马上被started。随后的producer直到前一个发送完成后才会start。一有失败立即传到外层。
<pre><code>
let (producerA, lettersObserver) = SignalProducer<String, NoError>.buffer(5)
let (producerB, numbersObserver) = SignalProducer<String, NoError>.buffer(5)
let (signal, observer) = SignalProducer<SignalProducer<String, NoError>, NoError>.buffer(5)
signal.flatten(.Concat).startWithNext { next in print(next) }
observer.sendNext(producerA)
observer.sendNext(producerB)
observer.sendCompleted()
numbersObserver.sendNext("1") // nothing printed
lettersObserver.sendNext("a") // prints "a"
lettersObserver.sendNext("b") // prints "b"
numbersObserver.sendNext("2") // nothing printed
lettersObserver.sendNext("c") // prints "c"
lettersObserver.sendCompleted() // prints "1", "2"
numbersObserver.sendNext("3") // prints "3"
numbersObserver.sendCompleted()
</code></pre>
转向最新的流
<code> .Latest </code>只接收最新进来的那个流的值。
<pre><code>
let (producerA, observerA) = SignalProducer<String, NoError>.buffer(5)
let (producerB, observerB) = SignalProducer<String, NoError>.buffer(5)
let (producerC, observerC) = SignalProducer<String, NoError>.buffer(5)
let (signal, observer) = SignalProducer<SignalProducer<String, NoError>, NoError>.buffer(5)
signal.flatten(.Latest).startWithNext { next in print(next) }
observer.sendNext(producerA) // nothing printed
observerC.sendNext("X") // nothing printed
observerA.sendNext("a") // prints "a"observerB.sendNext("1") // nothing printed
observer.sendNext(producerB) // prints "1"
observerA.sendNext("b") // nothing printed
observerB.sendNext("2") // prints "2"
observerC.sendNext("Y") // nothing printed
observerA.sendNext("c") // nothing printed
observer.sendNext(producerC) // prints "X", "Y"
observerB.sendNext("3") // nothing printed
observerC.sendNext("Z") // prints "Z"
</code></pre>
处理失败
下面这些操作符用户处理事件流产生的失败。
捕捉失败
<code> flatMapError </code>捕捉一个由SignalProducer产生的失败,然后产生一个新的SignalProducer代替。
<pre><code>
let (producer, observer) = SignalProducer<String, NSError>.buffer(5)
let error = NSError(domain: "domain", code: 0, userInfo: nil)
producer
.flatMapError { _ in SignalProducer<String, NoError>(value: "Default") }
.startWithNext { next in print(next) }
observer.sendNext("First") // prints "First"
observer.sendNext("Second") // prints "Second"
observer.sendFailed(error) // prints "Default"
</code></pre>
重试
<code> retry </code>用于按照指定次数,在失败时重启SignalProducer。
<pre><code>
var tries = 0
let limit = 2
let error = NSError(domain: "domain", code: 0, userInfo: nil)
let producer = SignalProducer<String, NSError> { (observer, _) in
if tries++ < limit {
observer.sendFailed(error)
} else {
observer.sendNext("Success")
observer.sendCompleted()
}
}
producer
.on(failed: {e in print("Failure")}) // 打印 "Failure" 两次
.retry(2)
.start { event in
switch event { case let .Next(next): print(next) // 打印 "Success"
case let .Failed(error):
print("Failed: (error)")
case .Completed:
print("Completed")
case .Interrupted:
print("Interrupted")
}
}
</code></pre>
如果按照指定次数还没有成功,就会输出失败。
映射错误 (Mapping errors)
<code> mapError </code>会将事件流里的任何一个失败映射成一个新的错误。
产生(Promote)
<code> promoteErrors </code> 可以在一个正常的流里产生一个错误,类似throw。
<pre><code>
let (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe()
let (lettersSignal, lettersObserver) = Signal<String, NSError>.pipe()
numbersSignal
.promoteErrors(NSError)
.combineLatestWith(lettersSignal)
</code></pre>
欢迎关注我的微博:@没故事的卓同学