文檔地址: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>
歡迎關注我的微博:@沒故事的卓同學