RxSwift 之 Observable

BigNerdCoding發表於2019-03-01

Cover
Cover

在前一篇基礎之上,本文我們將會介紹 RxSwift 中的 Observables 部分。

在 RxSwift 中 Observable 也被稱為 Observable Sequence、Sequence、Stream。Observable 會以非同步的方式不斷的發射事件形成事件流,並且資料也會沿著事件流進行傳播。下圖是事件流的影象化表示:

2017-09-07-01
2017-09-07-01

其中從左到右的箭頭代表時間軸,而三個圓圈則構成了可觀察序列。而整個過程會按照從左到右的順序。另外,事件可能在可觀察序列生命週期內的任意時刻被觸發。

Observable 生命週期

上圖中的三個圓圈其實就是 RxSwift 中的 next 事件。除了 next 之外,RxSwift 中還有 completederror 事件,而這兩者都意味事件流生命週期的總結。

completed 所表示的正常終結:

2017-09-07-02
2017-09-07-02

error 所表示的異常終結:

2017-09-07-03
2017-09-07-03

在原始碼中這三類事件的定義如下:

/// Represents a sequence event.
///
/// Sequence grammar: 
/// **next\* (error | completed)**
public enum Event<Element> {
    /// Next element is produced.
    case next(Element)

    /// Sequence terminated with an error.
    case error(Swift.Error)

    /// Sequence completed successfully.
    case completed
}複製程式碼

在程式碼中,我們可以清晰的看到 next 事件會攜帶一個例項進行傳播,error 事件會攜帶一個 Error 例項,completed 則什麼都不會攜帶。

新建 Observable

在所有 Observable 物件的建立方法中,最簡單的就是 just

// 1
let one = 1 
let two = 2 
let three = 3

// 2 
let observable: Observable<Int> = Observable<Int>.just(one)複製程式碼

作為類方法 just 所建立的 Observable 物件只會包含一個元素。但是大多數時候,Observable 物件在其生命週期內會包含多個元素,而建立方法也很簡單:

let observable2 = Observable.of(one, two, three)複製程式碼

可能上面的程式碼會給人一種誤導,讓人覺得 observable2 中的資料可能是一個陣列型別。不過好在我們可以通過下面的程式碼進行檢驗:

observable2.subscribe(onNext: { element in
        print(element)    
 })

/* 列印結果:
1
2
3
*/複製程式碼

而真正建立陣列型別變數的方法是:

let observable3 = Observable.of([one, two, three])
observable3.subscribe(onNext: { element in
        print(element)    
 })

/* 列印結果:
[1, 2, 3]
*/複製程式碼

上面只是幾個常用的 Observable 建立方法,更多的內容可以去查文件和程式碼。

訂閱 Observable

在日常 iOS 程式設計中,通知模式可以說是使用頻率相當高的一個設計模式。我們通過 NotificationCenter 實現訊息的廣播和訂閱。下面是一個典型的通知模式程式碼用於處理 UIKeyboardDidChangeFrame 訊息:

let observer = NotificationCenter.default.addObserver( 
forName: .UIKeyboardDidChangeFrame, 
object: nil, 
queue: nil ) {  notification in 
    // 閉包
}複製程式碼

RxSwift 中的訂閱操作也非常簡單,只需要呼叫 subscribe 方法就行了。不過與 NotificationCenter 機制不同的是,RxSwift 中每一個訂閱都是唯一的並沒有一個類似 default 這樣的全域性單例物件。

更為重要的是,在沒有訂閱者的時候 Observable 物件不會傳送通知。另外, Observable 物件實際上是一個序列,所以訂閱操作有點類似於反覆呼叫 Swift 標準庫裡中迭代器 Iterator 物件 next 函式:

let sequence = 0..<3

var iterator = sequence.makeIterator()

while let n = iterator.next() { 
    print(n)
}

/* 列印結果: 
0 1 2 
*/複製程式碼

不過 RxSwift 訂閱操作明顯比這個來的更直接,並且可以一次實現對 nexterrorcompleted 事件的的處理。一個簡單的訂閱操作示例:

let one = 1 
let two = 2 
let three = 3

let observable = Observable.of(one, two, three)

observable.subscribe { event in 
    print(event) 
}複製程式碼

上面程式碼的訂閱操作非常簡單:列印出 observable 宣告週期內的所有事件。正常情形下,它的結果如下:

next(1) 
next(2) 
next(3) 
completed複製程式碼

當然,有時候我們可能只是需要 observable 所發射的資料:

observable.subscribe { event in
    if let element = event.element { 
        print(element)
    }
}

/* 列印結果:
1 
2 
3
*/複製程式碼

又或者,我們需要對不同事件區別處理:

observable .subscribe(
    onNext: { element in 
        print(element) 
    },
    onCompleted: { 
        print("Completed")

    }
)複製程式碼

取消訂閱並消除記憶體洩漏

Observable 物件只有在存在訂閱的情形下才會進行資料傳送操作,而且會在 errorcompleted 事件觸發時結束其生命週期。但是,有時候我們可能需要手動取消訂閱並提前終結 Observable 物件的生命。

let observable = Observable.of("A", "B", "C")

let subscription = observable.subscribe { event in
    print(event)
}複製程式碼

上面程式碼非常簡單這裡就不再細訴了,這裡我們直接來看取消訂閱的操作。其實,取消訂閱的操作非常之簡單隻需一行程式碼:

subscription.dispose()複製程式碼

當然,手動對每一個訂閱物件進行取消操作顯然是一件枯燥的工作。所以 RxSwift 為大家提供了一個更為簡單的方案。只需在訂閱時呼叫 .addDisposableTo() 新增一個 DisposeBag 型別物件,我們就能在 DisposeBag 物件銷燬時取消所有繫結訂閱物件的取消動作。

let disposeBag = DisposeBag()

Observable.of("A", "B", "C")
    .subscribe { 
        3 print($0)
    } 
    .addDisposableTo(disposeBag)複製程式碼

這裡我們之所以需要進行 DisposeBag 物件繫結或者手動呼叫 dispose() 進行取消訂閱操作,是因為如果不這麼做的話 Observable 物件在生命週期完結時會存在記憶體洩漏的問題。

總結

本文只是簡單的介紹了 Observables 一些常見基礎內容。這裡還有很多更深入的內容沒有介紹,例如:emptynever 型別的訂閱、使用 Create 實現自定義 Observable 以及 Error 型別的自定義實現。如果你有興趣的話,我強烈建議你查閱官方文件和程式碼。

原文地址

相關文章