隨著Swift引入了型別安全的特性(泛型、型別推斷),在RAC 3.0+後的使用與OC的RAC 2.5已經有了很大的不同。
RAC 4 與 2.5訊號的一個最大的區別就是強制區分出了熱訊號和冷訊號。在2.5中無論冷熱的訊號都是RACSignal,在4.0+後熱訊號由Signal表示,冷訊號由SignalProducer表示。具體的瞭解可以參照我之前翻譯的一篇官方文件:《ReactiveCocoa 4 文件翻譯:框架組成介紹》。
建立熱訊號:Signal
直接看下官方playground裡的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
let (signal, observer) = Signal.pipe() let subscriber1 = Observer(next: { print("Subscriber 1 received \($0)") } ) let subscriber2 = Observer(next: { print("Subscriber 2 received \($0)") } ) signal.observe(subscriber1) //只有subscriber1收到了資料10 observer.sendNext(10) // subscriber2也訂閱了訊號 signal.observe(subscriber2) //subscriber1,subscriber2都收到了20 observer.sendNext(20) |
假設這裡是要建立一個熱訊號,那麼用的是Signal下的靜態方法:pipe()。
這個方法的泛型引數有兩個:第一個表示訊號裡帶的value的型別,第二個參數列示發生failed事件時,帶的error的型別。返回值是是一個tuple,第一個值是建立的signal,第二個是用來手動控制傳送事件的observer。
接著建立了兩個訂閱者。訂閱者Observer是一個結構體,兩個泛型引數和Signal一樣,表示next事件和failed事件中值的型別。
Observer可以訂閱四種事件,初始化時可以傳入對應的閉包對響應的事件做處理。這裡直接貼出Observer的初始化原始碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public init(failed: (Error -> ())? = nil, completed: (() -> ())? = nil, interrupted: (() -> ())? = nil, next: (Value -> ())? = nil) { self.init { event in switch event { case let .Next(value): next?(value) case let .Failed(error): failed?(error) case .Completed: completed?() case .Interrupted: interrupted?() } } } |
因為四種事件都是可選的閉包,並且帶了預設值,所以初始化時要注意自己需要處理幾種事件,根據引數名傳入對應的閉包。前面的demo中只處理next事件。
然後可以用pipe()返回的訊號的對應的observer來傳送事件。在前面示例中 observer.sendNext(10)
傳送了一個next事件。也可以傳送Failed、Completed、Interrupted事件。
建立冷訊號:SignalProducer
SignalProducer的訊號行為是冷訊號,即每個訂閱者訂閱的時候都會觀察到相同的所有發出的事件。Signal是熱訊號,只會接收到訂閱後發出的事件。
直接看下官方playground裡的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 |
let producer = SignalProducer { observer, disposable in observer.sendNext(1) observer.sendNext(2) } let subscriber1 = Observer(next: { print("Subscriber 1 received \($0)") }) let subscriber2 = Observer(next: { print("Subscriber 2 received \($0)") }) producer.start(subscriber1) // subscriber1,subscriber2都會收到發出的1,2的值 producer.start(subscriber2) |
SignalProducer初始化的泛型引數和signal一樣,但是隻返回一個SignalProducer物件,observer做作為初始化閉包中的一個引數,和2.5中RACSignal初始化函式類似。
注意SignalProducer新增訂閱者的方法與Signal不同,使用的是start()方法。這樣的語義也更明白一些。
empty訊號
一個empty訊號指馬上就傳送completed事件,沒有任何其他值。
1 2 3 |
let emptySignal = Signal.empty let emptyProducer = SignalProducer.empty |
都是呼叫一個靜態的合成屬性empty。
1 2 3 4 5 6 |
public static var empty: Signal { return self.init { observer in observer.sendCompleted() return nil } } |
其實實現也很簡單,就是初始化後馬上傳送一個完成的事件
empty的一個使用場景是作為一個高階訊號的value,有時一個產生訊號的訊號,裡面這個訊號的值可能並不重要,value就會放一個empty訊號
never訊號
never訊號是一個不傳送任何事件的訊號。
1 2 |
let neverSignal = Signal.never let neverProducer = SignalProducer.never |
這個的實現也很簡答,就是初始化以後什麼都不做。
1 2 3 |
public static var never: SignalProducer { return self.init { _ in return } } |
never通常也是使用在高階函式的操作裡,可以用來表示一個不會結束的訊號。
歡迎關注我的微博:@沒故事的卓同學