iOS開發(fā)進階 - RxSwift之Observable

來自網(wǎng)絡

RxSwift-Reactive Programming with Swift (Swift4.0)

Observables

ObservablesRx的核心鞋囊,本節(jié)將花點時間學習如何創(chuàng)建和使用Observables。在RxSwift中溜腐,Observables瓜喇、Observables sequencesequence代表相同的意思,RxSwift的世界里望众,任何事物都是序列伞辛。observable也是序列,它可以產(chǎn)生事件甘耿,事件可以包含值佳恬。

Observables三種狀態(tài)和生命周期

Observables有三種狀態(tài)分別是next于游、errorcompleted。下面使用圓珠圖(marble diagram)理解Observables的生命周期头谜。

圖片來自RxSwift

上圖中從左到右的箭頭代表時間柱告,線上的圓珠代表序列事件元素。隨著時間的推移線上的元素會被依次發(fā)射葵袭。observable發(fā)射元素產(chǎn)生next事件。

另一張圓珠圖乖菱,它存在一個結束線坡锡。

來自RxSwift

observable發(fā)射三個tap事件,當結束時會發(fā)個completed事件作為序列的結束標志窒所。例如:tap所在的界面銷毀鹉勒。在observable結束后不再發(fā)送任何事件,這種結束方式屬于正常終止吵取。

另外禽额,存在一種非正常方式結束序列,如出現(xiàn)錯誤時皮官,如下面這張圖脯倒。


來自RxSwift

當錯誤發(fā)送時藻丢,observable發(fā)射error事件此時序列終止不再發(fā)射任何事件悠反。

回顧一下上面三張圖:

隨著時間推移序列會根據(jù)元素依次發(fā)送next事件斋否,兩種情況導致序列結束如叼,第一穷劈,發(fā)生錯誤發(fā)射error事件序列終止歇终,第二评凝,發(fā)射completed事件序列終止奕短。序列一旦終止就不會再發(fā)射任何事件。

Swift中谬返,事件是枚舉類型的結構如下:

/// 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攜帶一個泛型Element
  • ②:error攜帶一個Swift.Error實例對象莉擒。
  • ③:completed表示序列結束不攜帶值涨冀。

創(chuàng)建Observables

了解了Observables概念接下學習如何創(chuàng)建和使用Observables廷支。

RxSwift提供多種方式創(chuàng)建Observables栓辜。例如:of, just, from, empty, neverrange等藕甩。

just: 創(chuàng)建單個事件的序列僵娃。of: 創(chuàng)建多個事件的序列腋妙。from: 通過數(shù)組創(chuàng)建多個事件的序列匙睹。empty創(chuàng)建一個空的序列痕檬,只發(fā)射completed事件送浊。never創(chuàng)建一個不發(fā)射事件也不會結束的序列。range(start, count):創(chuàng)建包含多個事件的序列闭树。

// 1. 創(chuàng)建Observables
example(of: "just of from") {
    // 1
    let one = 1
    let two = 2
    let three = 3
    // 2
    let observable1 = Observable.just(one)
    // 3 
    let observable2 = Observable.of(one, two, three)
    let observable3 = Observable.of([one, two, three]) // [Int]
    // 4 
    let observable4 = Observable.from([one, two, three])
    let observable5 = Observable<Void>.empty()
    let observable6 = Observable<Any>.never()
    let observable7 = Observable.range(start: 1, count: 5)
}
  1. 定義三個常量。
  2. 使用just創(chuàng)建只有一個元素的序列捏肢,此時序列類型為Observable<Int>饥侵。
  3. 使用of創(chuàng)建序列躏升,注意Observable2Observable<Int>膨疏,而observable3Observable<[Int]>類型 佃却。
  4. 使用from創(chuàng)建序列饲帅,此時接收的參數(shù)是數(shù)組類型灶泵。注意:與of的區(qū)別赦邻。

除了前面的創(chuàng)建方式還可以使用create創(chuàng)建序列惶洲。

// Create方法湃鹊,內(nèi)部有一個observer
example(of: "Create") {
   // 1
    let disposeBag = DisposeBag()
    // 2 
    Observable<String>.create { observer in
       
        observer.onNext("1")
        observer.onCompleted()
        observer.onNext("2")
        // 3
        return Disposables.create()
    }
    // 4
    .subscribe(
               onNext: {print($0)},
               onError: {print($0)},
               onCompleted: {print("Completed")},
               onDisposed: {print("Disposed")}
    )
    // 5
    .disposed(by: disposeBag)
}
  1. 創(chuàng)建一個DisposeBag對象,用于管理序列
  2. create方法參數(shù)是一個逃逸閉包參數(shù)為AnyObserver返回值Disposable類型。AnyObserver是通用類型用來將值添加到序列中芯义,在將來發(fā)射給訂閱者扛拨。
  3. 返回disposable代表訂閱,Disposables.create()創(chuàng)建了一個空的disposable央渣。
  4. 通過subscribe訂閱芽丹,運行結果你會發(fā)現(xiàn)沒有輸出2拔第,因為在onNext("2")之前懈涛,已經(jīng)發(fā)送completed事件序列終止泳猬。
  5. 添加到bag中暂殖。

訂閱序列

訂閱序列使用.subscribe方法踩窖。直接看示例代碼:

// 訂閱
example(of: "subscrible") {
    let one = 1
    let two = 2
    let three = 3
    // 1
    let observable = Observable.from([one ,two, three])
    // 2 第一種
    observable.subscribe { event in
        print(event)  // 輸出事件
        if let element = event.element {
            print(element)
        }
    }
     // 3 另一種方式
   observable.subscribe(onNext: { (element) in
        print(element)
    }, onError: { (error) in
        print(error)
    }, onCompleted: {
        print("completed")
    }, onDisposed: {
        print("disposed")
    })
}
  1. 創(chuàng)建有多個元素的序列洋腮。
  2. 使用func subscribe(_ on: @escaping (Event<Int>) -> Void) -> Disposable方法訂閱序列啥供,逃逸閉包參數(shù)是Int類型的事件伙狐。方法返回值是Disposable罢防。Disposable稍后會學到咒吐。閉包中參數(shù)是事件恬叹,通過事件的可選值element參數(shù)獲取值。
  3. 另一個方法相對方便嗽测,直接可以獲取到事件的值唠粥。注意:onError大莫、onCompletedonDisposed是可選的只厘。

清除和終止

Observable為被訂閱時羔味,不會發(fā)射任何事件赋元,當出現(xiàn)錯誤或結束時才會終止。不過狠毯,也可以通過清除訂閱來終止序列嫡良。

每一個訂閱者都存在一個dispose方法皆刺,當調(diào)用該方法時會清除訂閱者羡蛾。示例代碼:

// dispose 用于回收,防止內(nèi)存泄露
example(of: "dispose") {
    let observable = Observable.of("A", "B", "C")
    let subscription = observable.subscribe {event in
        print(event)
    }
    subscription.dispose()
}

example(of: "DisposeBag") {
    let disposeBag = DisposeBag()
    Observable.of("A", "B", "C")
        .subscribe {
            print($0)
    }
    .disposed(by: disposeBag)
}
  • DisposeBag清除包浪藻,通過調(diào)用dispose方法爱葵,取消訂閱并且釋放內(nèi)部資源萌丈。

三種特殊的Observable

  • Single:不同于Observable它只會發(fā)送nexterror事件。Observable通過調(diào)用asSingle方法可以轉(zhuǎn)換成Single度迂。
    通常用于網(wǎng)絡下載或者讀取磁盤數(shù)據(jù)惭墓。
example(of: "Single") {
    // 1
    let disposeBag = DisposeBag()

    // 2
    enum FileError: Error {
        case  fileNotFound, unreadable, encodingFailed
    }
    // 3
    func loadText(from name: String) -> Single<String> {
        // 4
        return Single.create { single in
            let disposable = Disposables.create()

            guard let path = Bundle.main.path(forResource: name, ofType: "txt") else {
                single(.error(FileError.fileNotFound))
                return disposable
            }

            guard let data = FileManager.default.contents(atPath: path) else {
                single(.error(FileError.unreadable))
                return disposable
            }
            guard let content = String(data: data, encoding: .utf8) else {
                single(.error(FileError.encodingFailed))
                return disposable
            }
            single(.success(content))
            return disposable
        }
    }

    loadText(from: "Copyright")
        .subscribe {
            switch $0 {
            case .success(let str):
                print(str)
            case .error(let error):
                print(error)
            }
    }
    .disposed(by: disposeBag)
}
  • Completable:只會發(fā)送completederror事件毅人。只關心任務是否完成不關心返回值丈莺,類似Observable<Void>
  • Maybe: 介于CompletableSingle之間弛秋,只會發(fā)送一個元素。

本節(jié)是對RxSwiftObservable概念和使用的初步學習登失,循序漸進逐步深入學習深層次內(nèi)容。

小結

  • Observables是什么馅巷?生命周期钓猬?
  • Observables 創(chuàng)建方法有哪些敞曹?
  • 如何訂閱Observable?
  • DisposeBag是什么异雁?它的作用是什么?

參考

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市暂论,隨后出現(xiàn)的幾起案子展哭,更是在濱河造成了極大的恐慌匪傍,老刑警劉巖役衡,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榕莺,死亡現(xiàn)場離奇詭異钉鸯,居然都是意外死亡,警方通過查閱死者的電腦和手機及塘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灵再,“玉大人翎迁,你說我怎么就攤上這事∷喟荩” “怎么了士聪?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長区岗。 經(jīng)常有香客問我躏尉,道長胀糜,這世上最難降的妖魔是什么教藻? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任碌秸,我火速辦了婚禮,結果婚禮上轧抗,老公的妹妹穿的比我還像新娘纠炮。我一直安慰自己恢口,他們只是感情好耕肩,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著两芳,像睡著了一般怖辆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逗余,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天画拾,我揣著相機與錄音青抛,去河邊找鬼蜜另。 笑死举瑰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的促煮。 我是一名探鬼主播菠齿,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼疾棵!你這毒婦竟也來了是尔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤恩溅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后滨达,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俯艰,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了昧甘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片充边。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肘习,靈堂內(nèi)的尸體忽然破棺而出漂佩,到底是詐尸還是另有隱情投蝉,我是刑警寧澤瘩缆,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布庸娱,位于F島的核電站,受9級特大地震影響氯夷,放射性物質(zhì)發(fā)生泄漏雇毫。R本人自食惡果不足惜棚放,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一馍迄、第九天 我趴在偏房一處隱蔽的房頂上張望攀圈。 院中可真熱鬧赘来,春花似錦、人聲如沸冰单。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甩挫。三九已至伊者,卻和暖如春亦渗,著一層夾襖步出監(jiān)牢的瞬間法精,已是汗流浹背狼荞。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留丰涉,地道東北人昔搂。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像逛裤,于是被迫代替她去往敵國和親带族。 傳聞我的和親對象是個殘疾皇子蝙砌,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容