文檔地址: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 文檔翻譯--設(shè)計指南(一):事件的規(guī)范
ReactiveCocoa 4 文檔翻譯:設(shè)計指南(二):信號的規(guī)范
[翻譯]ReactiveCocoa 4 最佳實踐
組合事件流
下面的操作符將多個事件流的值組合成一個統(tǒng)一的新的事件流竖配。
按照最新的值組合
<code> combineLatest </code>函數(shù)可以把幾個事件流最新的值組合成一個新的事件流进胯。
合成后的新事件流只有在收到每個合成流的至少一個值后才會發(fā)送出去胁镐。接著就會把每個流的最新的值一起輸出诸衔。
<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)廓旬。接著每有一個值輸入孕豹,就根據(jù)兩個流最近輸入的值輸出值怔蚌。
Zipping(拉鏈)
<code> zip </code>將兩個(或者多個)事件流的值成對組合桦踊。就像拉鏈一樣籍胯。將每個事件流的值按照索引順序組合輸出杖狼。意味著如果是一個流的第N個元素,一定要等到另外一個流第N值也收到才會一起組合發(fā)出理朋。
<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個值還沒有收到洼畅,所以沒有發(fā)出。
壓平信號產(chǎn)生源(Flattening producers)
<code> flatten </code> 將一個事件流里的事件流變成一個單一的事件流务热。新的事件流的值按照指定的策略(FlattenStrategy)由內(nèi)部的事件流的值組成崎岂。
被壓平的值按照會變成外層的流的類型冲甘。比如:一個SignalProducers里的Signal江醇,被flatten后的類型是SignalProducers何暇。
想象下面values里面的三組值的發(fā)出時間根據(jù)圖里的位置排列裆站。
簡單的說就是merge按照時間順序組成羽嫡,concat則是按照里面整個流順序組合肩袍。latest是只記錄最近一次過來的值的那個流氛赐。
合并
<code> .Merge </code> 策略將每個流的值立刻組合輸出。無論內(nèi)部還是外層的流如果收到失敗就終止甫窟。
<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> 策略是將內(nèi)部的SignalProducer排序。外層的producer是馬上被started街图。隨后的producer直到前一個發(fā)送完成后才會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>
轉(zhuǎn)向最新的流
<code> .Latest </code>只接收最新進(jìn)來的那個流的值蚁阳。
<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>
處理失敗
下面這些操作符用戶處理事件流產(chǎn)生的失敗螺捐。
捕捉失敗
<code> flatMapError </code>捕捉一個由SignalProducer產(chǎn)生的失敗定血,然后產(chǎn)生一個新的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>用于按照指定次數(shù)茫虽,在失敗時重啟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>
如果按照指定次數(shù)還沒有成功贤壁,就會輸出失敗脾拆。
映射錯誤 (Mapping errors)
<code> mapError </code>會將事件流里的任何一個失敗映射成一個新的錯誤。
產(chǎn)生(Promote)
<code> promoteErrors </code> 可以在一個正常的流里產(chǎn)生一個錯誤旨怠,類似throw鉴腻。
<pre><code>
let (numbersSignal, numbersObserver) = Signal<Int, NoError>.pipe()
let (lettersSignal, lettersObserver) = Signal<String, NSError>.pipe()
numbersSignal
.promoteErrors(NSError)
.combineLatestWith(lettersSignal)
</code></pre>
歡迎關(guān)注我的微博:@沒故事的卓同學(xué)