ObjectiveCBridging
RACSignal -> Signal, SignalProducer
RACCommand -> Action
RACScheduler -> SchedulerType
RACDisposable -> Disposable
具體可以參看ObjectiveCBridging.swift
RAC4的 Signal 對應RAC2的 RACSubject,為熱訊號,SignalProducer 對應 RACSignal 為冷訊號。
熱訊號是主動的,就算沒有訂閱者也會即刻推送;冷訊號是被動的,有訂閱者才推送
熱訊號可以有多個訂閱者,一對多;冷訊號只能一對一,當有新的訂閱者,訊號是重新完整傳送的
形象的說:熱訊號像是直播,冷訊號像是點播
熱訊號
參看一個例子
// 建立訊號
let (signal, observer) = Signal<String, NSError>.pipe()
// 監聽器1:立即監聽
signal.observeResult {
NSLog("Subscriber 1 get a next value: ($0)")
}
// 監聽器2:0.1s後監聽
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 0.1)) {
signal.observeResult({ (result) in
NSLog("Subscriber 2 get a next value: (result)")
})
}
// 傳送Next訊號:1s後傳送"package 1"
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
NSLog("Signal send package 1 ...")
observer.sendNext("package 1")
}
// 監聽器3:1.1s後監聽
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1.1)) {
signal.observeResult {
NSLog("Subscriber 3 get a next value: ($0)")
}
}
// 傳送Next訊號: 2s後傳送"package 2"
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 2)) {
NSLog("signal send package 2 ...")
observer.sendNext("package 2")
}
執行:
2016-12-18 19:42:16.206588 TestRAC4[695:389286] start ...
2016-12-18 19:42:17.249072 TestRAC4[695:389286] Signal send package 1 ...
2016-12-18 19:42:17.254583 TestRAC4[695:389286] Subscriber 1 get a next value: .Success(package 1)
2016-12-18 19:42:17.254899 TestRAC4[695:389286] Subscriber 2 get a next value: .Success(package 1)
2016-12-18 19:42:18.393983 TestRAC4[695:389286] signal send package 2 ...
2016-12-18 19:42:18.394386 TestRAC4[695:389286] Subscriber 1 get a next value: .Success(package 2)
2016-12-18 19:42:18.394582 TestRAC4[695:389286] Subscriber 2 get a next value: .Success(package 2)
2016-12-18 19:42:18.394769 TestRAC4[695:389286] Subscriber 3 get a next value: .Success(package 2)
正如之前提到的熱訊號的特點,熱訊號不關心是否有人監聽,有產生訊號就傳送,有人監聽就發個監聽者。0.1s,2s分別傳送next事件,0s,0.1s,1.1s分別產生一個監聽者,所以第一個訊號只有監聽者1,2能收到;第二個next發出時三個監聽器都準備好了,都能收到。
冷訊號
再看看冷訊號的例子:
let producer = SignalProducer<String, NSError>.init { (observer, _) in
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
NSLog("Producer send package 1 ...")
observer.sendNext("package 1")
}
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 2)) {
NSLog("Producer send package 2 ...")
observer.sendNext("package 2")
}
}
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 2)) {
NSLog("setup Subsrciber 1")
producer.startWithResult({ (msg) in
NSLog("Subscriber 1 get a next value: (msg)")
})
}
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 3)) {
NSLog("setup Subsrciber 2")
producer.startWithResult({ (msg) in
NSLog("Subscriber 2 get a next value: (msg)")
})
}
以下是輸出:
2016-12-18 20:05:36.396118 TestRAC4[703:394073] start ...
2016-12-18 20:05:38.600637 TestRAC4[703:394073] setup Subsrciber 1
2016-12-18 20:05:39.681697 TestRAC4[703:394073] setup Subsrciber 2
2016-12-18 20:05:39.682077 TestRAC4[703:394073] Producer send package 1 ...
2016-12-18 20:05:39.685559 TestRAC4[703:394073] Subscriber 1 get a next value: .Success(package 1)
2016-12-18 20:05:40.753463 TestRAC4[703:394073] Producer send package 2 ...
2016-12-18 20:05:40.753865 TestRAC4[703:394073] Subscriber 1 get a next value: .Success(package 2)
2016-12-18 20:05:40.754679 TestRAC4[703:394073] Producer send package 1 ...
2016-12-18 20:05:40.754898 TestRAC4[703:394073] Subscriber 2 get a next value: .Success(package 1)
2016-12-18 20:05:41.881230 TestRAC4[703:394073] Producer send package 2 ...
2016-12-18 20:05:41.881673 TestRAC4[703:394073] Subscriber 2 get a next value: .Success(package 2)
使用冷訊號,訊號在程式起來第1s,2s分別傳送了一個next。而在2s,3s分別建立了一個監聽。第一個監聽建立後1s,2s分別收到一個訊號。第二訊號建立的1s,2s後也分別收到了同樣的訊號。
冷訊號轉化為特殊熱訊號
由於冷訊號每次訂閱都重新傳送事件,故有時候我們需要多次訂閱時會造成不希望的重複傳送(這稱為訊號的副作用),我們需要將冷訊號轉為具有熱訊號特徵的冷訊號。
參看一個例子,我們用冷,熱訊號在0.1s後傳送三個next事件,然後如下進行監聽:
// 我們用2個監控來監控generateSignal()產生的訊號
let signal = generateSignal()
signal.startWithResult{ NSLog("Subscriber 1 get a next value: ($0)") }
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
signal.startWithResult{ NSLog("Subscriber 2 get a next value: ($0)") }
}
先看看如果是產生了普通的冷訊號:
func generateSignal() -> SignalProducer<String, NSError> {
let producer = SignalProducer<String, NSError>.init { (observer, _) in
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
NSLog("producer send package 1 ...")
observer.sendNext("package 1")
NSLog("producer send package 2 ...")
observer.sendNext("package 2")
NSLog("producer send package 3 ...")
observer.sendNext("package 3")
}
}
return producer
}
輸出如我們所料,訊號被重複傳送了。
2016-12-18 21:46:21.295670 TestRAC4[742:413995] start ...
2016-12-18 21:46:22.389634 TestRAC4[742:413995] producer send package 1 ...
2016-12-18 21:46:22.397032 TestRAC4[742:413995] Subscriber 1 get a next value: .Success(package 1)
2016-12-18 21:46:22.397397 TestRAC4[742:413995] producer send package 2 ...
2016-12-18 21:46:22.398235 TestRAC4[742:413995] Subscriber 1 get a next value: .Success(package 2)
2016-12-18 21:46:22.398415 TestRAC4[742:413995] producer send package 3 ...
2016-12-18 21:46:22.398608 TestRAC4[742:413995] Subscriber 1 get a next value: .Success(package 3)
2016-12-18 21:46:23.496484 TestRAC4[742:413995] producer send package 1 ...
2016-12-18 21:46:23.496886 TestRAC4[742:413995] Subscriber 2 get a next value: .Success(package 1)
2016-12-18 21:46:23.497061 TestRAC4[742:413995] producer send package 2 ...
2016-12-18 21:46:23.497255 TestRAC4[742:413995] Subscriber 2 get a next value: .Success(package 2)
2016-12-18 21:46:23.497413 TestRAC4[742:413995] producer send package 3 ...
2016-12-18 21:46:23.498869 TestRAC4[742:413995] Subscriber 2 get a next value: .Success(package 3)
如果改成熱訊號呢?
func generateSignal() -> Signal<String, NSError> {
let (signal, observer) = Signal<String, NSError>.pipe()
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 0.1)) {
NSLog("producer send package 1 ...")
observer.sendNext("package 1")
NSLog("producer send package 2 ...")
observer.sendNext("package 2")
NSLog("producer send package 3 ...")
observer.sendNext("package 3")
}
return signal
}
let signal = generateSignal()
signal.observeResult { NSLog("Subscriber 1 get a next value: ($0)") }
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
signal.observeResult{ NSLog("Subscriber 2 get a next value: ($0)") }
}
輸出也如我們所料,只有監聽2能搜到事件,且訊號都只傳送一次。
2016-12-18 21:54:34.527911 TestRAC4[745:415500] start ...
2016-12-18 21:54:34.634711 TestRAC4[745:415500] producer send package 1 ...
2016-12-18 21:54:34.637899 TestRAC4[745:415500] Subscriber 1 get a next value: .Success(package 1)
2016-12-18 21:54:34.638067 TestRAC4[745:415500] producer send package 2 ...
2016-12-18 21:54:34.638146 TestRAC4[745:415500] Subscriber 1 get a next value: .Success(package 2)
2016-12-18 21:54:34.638195 TestRAC4[745:415500] producer send package 3 ...
2016-12-18 21:54:34.638334 TestRAC4[745:415500] Subscriber 1 get a next value: .Success(package 3)
緩衝 buffer
通過SignalProducer.buffer()建立,是一個事件的佇列(通常指定數量),當新訊號產生時,會重新執行佇列裡的事件。和pipe相似,這個方法返回一個觀察者。每個發給這個觀察者的事件會被加入佇列。如果這個緩衝區已經達到建立時預定的數量,當新的事件發來時,最早的一個會被移出佇列。
如果使用buffer來處理呢?我們將上面的冷訊號稍作修改:
func generateSignal() -> SignalProducer<String, NSError> {
let (producer, observer) = SignalProducer<String, NSError>.buffer(Int.max)
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
NSLog("producer send package 1 ...")
observer.sendNext("package 1")
NSLog("producer send package 2 ...")
observer.sendNext("package 2")
NSLog("producer send package 3 ...")
observer.sendNext("package 3")
}
return producer
}
輸出發現,似乎冷訊號變成了熱訊號了,只傳送了一次。但又具有冷訊號的特點:兩個監聽器都能收到事件。
2016-12-18 21:44:29.971493 TestRAC4[740:413482] start ...
2016-12-18 21:44:31.071352 TestRAC4[740:413482] producer send package 1 ...
2016-12-18 21:44:31.075839 TestRAC4[740:413482] Subscriber 1 get a next value: .Success(package 1)
2016-12-18 21:44:31.076115 TestRAC4[740:413482] producer send package 2 ...
2016-12-18 21:44:31.076580 TestRAC4[740:413482] Subscriber 1 get a next value: .Success(package 2)
2016-12-18 21:44:31.076773 TestRAC4[740:413482] producer send package 3 ...
2016-12-18 21:44:31.077035 TestRAC4[740:413482] Subscriber 1 get a next value: .Success(package 3)
2016-12-18 21:44:31.078167 TestRAC4[740:413482] Subscriber 2 get a next value: .Success(package 1)
2016-12-18 21:44:31.078420 TestRAC4[740:413482] Subscriber 2 get a next value: .Success(package 2)
2016-12-18 21:44:31.078771 TestRAC4[740:413482] Subscriber 2 get a next value: .Success(package 3)
buffer(Int.max)這裡的參數列示這個緩衝大小,如果設定為1,那麼第二個next發出時,快取裡第一個就被替換成了第二個next,第三個來時同理。對於第一個監聽者它能收到全部事件;對於第二個監聽者只能收到快取裡的事件也就是最後的package 3。如果這第一個監聽者在發出訊號之後再開始監聽,那麼它也將和第二個監聽者一樣只能收到緩衝裡的事件。
replayLazily
假如我們不能修generateSignal()裡的程式碼,這是由第三方提供的,我們可以使用replayLazily。
let producer = generateSignal().replayLazily(Int.max) // 直接用之前的冷訊號
producer.startWithResult { NSLog("Subscriber 1 get a next value: ($0)") }
QueueScheduler.mainQueueScheduler.scheduleAfter(NSDate(timeIntervalSinceNow: 1)) {
producer.startWithResult { NSLog("subscriber 2 get a next value: ($0)") }
}
輸出如下,和buffer是一樣的效果:
2016-12-18 22:04:48.364076 TestRAC4[753:417953] start ...
2016-12-18 22:04:48.482124 TestRAC4[753:417953] producer send package 1 ...
2016-12-18 22:04:48.484271 TestRAC4[753:417953] Subscriber 1 get a next value: .Success(package 1)
2016-12-18 22:04:48.484422 TestRAC4[753:417953] producer send package 2 ...
2016-12-18 22:04:48.484665 TestRAC4[753:417953] Subscriber 1 get a next value: .Success(package 2)
2016-12-18 22:04:48.484852 TestRAC4[753:417953] producer send package 3 ...
2016-12-18 22:04:48.485120 TestRAC4[753:417953] Subscriber 1 get a next value: .Success(package 3)
2016-12-18 22:04:49.454274 TestRAC4[753:417953] subscriber 2 get a next value: .Success(package 1)
2016-12-18 22:04:49.454659 TestRAC4[753:417953] subscriber 2 get a next value: .Success(package 2)
2016-12-18 22:04:49.454897 TestRAC4[753:417953] subscriber 2 get a next value: .Success(package 3)
那麼replayLazily(Int.max)這個引數和buffer的相同嗎?我們修改成1或2一看就知道。答案是相同