RxSwift 實(shí)踐(一)簡(jiǎn)述

簡(jiǎn)介

它拓展了觀察者模式。使你能夠自由組合多個(gè)異步事件畜晰,而不需要去關(guān)心線程,同步瑞筐,線程安全舷蟀,并發(fā)數(shù)據(jù)以及I/O阻塞。

函數(shù)響應(yīng)式編程

  • 函數(shù)式編程:是種編程范式面哼,它需要我們將函數(shù)作為參數(shù)傳遞,或者作為返回值返還扫步。我們可以通過(guò)組合不同的函數(shù)來(lái)得到想要的結(jié)果魔策。
  • 響應(yīng)式編程: a=b+c表示將表達(dá)式的結(jié)果賦給 a,而之后改變 b 或 c的值不會(huì)影響 a河胎。但在響應(yīng)式編程中闯袒,a的值會(huì)隨著 b或 c的更新而更新。a=b+c聲明的是一種綁定關(guān)系游岳。

RxSwift優(yōu)點(diǎn)

  • 在業(yè)務(wù)層面實(shí)現(xiàn)代碼邏輯分離政敢,方便后期維護(hù)和拓展
  • 極大提高程序響應(yīng)速度,充分發(fā)掘CPU的能力
  • 幫助開(kāi)發(fā)者提高代碼的抽象能力和充分理解業(yè)務(wù)邏輯
  • Rx豐富的操作符會(huì)幫助我們極大的簡(jiǎn)化代碼邏輯

核心

  • Observable - 可被監(jiān)聽(tīng)的序列產(chǎn)列
  • Observer - 觀察者
  • Operator - 操作符
  • Disposable - 管理綁定(訂閱)的生命周期
  • Schedulers - 調(diào)度器(線程隊(duì)列調(diào)配)

Observable - 可被監(jiān)聽(tīng)的序列

框架已經(jīng)幫我們創(chuàng)建好了許多常用的序列胚迫。例如:button的點(diǎn)擊喷户,textField的當(dāng)前文本,switch的開(kāi)關(guān)狀態(tài)访锻,slider的當(dāng)前數(shù)值等等褪尝。

let numbers: Observable<Int> = Observable.create { observer -> Disposable in

    observer.onNext(0)
    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)
    observer.onNext(4)
    observer.onNext(5)
    observer.onNext(6)
    observer.onNext(7)
    observer.onNext(8)
    observer.onNext(9)
    observer.onCompleted()

    return Disposables.create()
}

Observer - 觀察者

觀察者最直接的方法就是在 Observable 的 subscribe 方法后面描述,事件發(fā)生時(shí)期犬,需要如何做出響應(yīng)河哑。而觀察者就是由后面的 onNext,onError龟虎,onCompleted的這些閉包構(gòu)建出來(lái)的璃谨。

  • observer.onNext(0) 就代表產(chǎn)生了一個(gè)元素,他的值是 0鲤妥。
  • onCompleted()結(jié)束
  • onError()發(fā)生錯(cuò)誤
tap.subscribe(onNext: { [weak self] in
    self?.showAlert()
}, onError: { error in
    print("發(fā)生錯(cuò)誤: \(error.localizedDescription)")
}, onCompleted: {
    print("任務(wù)完成")
})

操作符

  • filter - 過(guò)濾
// 溫度
let rxTemperature: Observable<Double> = ...

// filter 操作符
rxTemperature.filter { temperature in temperature > 33 }
    .subscribe(onNext: { temperature in
        print("高溫:\(temperature)度")
    })
    .disposed(by: disposeBag)
  • map - 轉(zhuǎn)換
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
    .map { $0 * 10 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
  • zip - 配對(duì)
let disposeBag = DisposeBag()
let first = PublishSubject<String>()
let second = PublishSubject<String>()

Observable.zip(first, second) { $0 + $1 }
          .subscribe(onNext: { print($0) })
          .disposed(by: disposeBag)

first.onNext("1")
second.onNext("A")
1A

Disposable - 可被清除的資源

通常來(lái)說(shuō)佳吞,一個(gè)序列如果發(fā)出了 error 或者 completed 事件,那么所有內(nèi)部資源都會(huì)被釋放旭斥。如果你需要提前釋放這些資源或取消訂閱的話容达,那么你可以對(duì)返回的 可被清除的資源(Disposable) 調(diào)用 dispose 方發(fā)

通常情況下,我們不需要手動(dòng)調(diào)用 dispose 方法的

使用 清除包(DisposeBag) 或者 takeUntil 操作符 來(lái)管理訂閱的生命周期

  • DisposeBag - 清除包
var disposeBag = DisposeBag()

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    textField.rx.text.orEmpty
        .subscribe(onNext: { text in print(text) })
        .disposed(by: self.disposeBag)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    self.disposeBag = DisposeBag()
}
  • takeUntil
    使得訂閱一直持續(xù)到控制器的 dealloc 事件產(chǎn)生為止
override func viewDidLoad() {
    super.viewDidLoad()

    ...

    _ = usernameValid
        .takeUntil(self.rx.deallocated)
        .bind(to: passwordOutlet.rx.isEnabled)

    _ = usernameValid
        .takeUntil(self.rx.deallocated)
        .bind(to: usernameValidOutlet.rx.isHidden)

    _ = passwordValid
        .takeUntil(self.rx.deallocated)
        .bind(to: passwordValidOutlet.rx.isHidden)

    _ = everythingValid
        .takeUntil(self.rx.deallocated)
        .bind(to: doSomethingOutlet.rx.isEnabled)

    _ = doSomethingOutlet.rx.tap
        .takeUntil(self.rx.deallocated)
        .subscribe(onNext: { [weak self] in self?.showAlert() })
}

Schedulers - 調(diào)度器

Schedulers 是 Rx 實(shí)現(xiàn)多線程的核心模塊垂券,它主要用于控制任務(wù)在哪個(gè)線程或隊(duì)列運(yùn)行花盐。
GCD:

// 后臺(tái)取得數(shù)據(jù)羡滑,主線程處理結(jié)果
DispatchQueue.global(qos: .userInitiated).async {
    let data = try? Data(contentsOf: url)
    DispatchQueue.main.async {
        self.data = data
    }
}

RxSwift:

let rxData: Observable<Data> = ...

rxData
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { [weak self] data in
        self?.data = data
    })
    .disposed(by: disposeBag)
  • subscribeOn 來(lái)決定數(shù)據(jù)序列的構(gòu)建函數(shù)在哪個(gè) Scheduler 上運(yùn)行。以上例子中算芯,由于獲取 Data 需要花很長(zhǎng)的時(shí)間柒昏,所以用 subscribeOn 切換到 后臺(tái) Scheduler 來(lái)獲取 Data。這樣可以避免主線程被阻塞熙揍。

  • observeOn 來(lái)決定在哪個(gè) Scheduler 監(jiān)聽(tīng)這個(gè)數(shù)據(jù)序列职祷。以上例子中,通過(guò)使用 observeOn 方法切換到主線程來(lái)監(jiān)聽(tīng)并且處理結(jié)果届囚。

  • MainScheduler 主線程

  • SerialDispatchQueueScheduler
    抽象了串行 DispatchQueue有梆。如果你需要執(zhí)行一些串行任務(wù),可以切換到這個(gè) Scheduler 運(yùn)行意系。

  • ConcurrentDispatchQueueScheduler
    抽象了并行 DispatchQueue泥耀。如果你需要執(zhí)行一些并發(fā)任務(wù),可以切換到這個(gè) Scheduler 運(yùn)行蛔添。

  • OperationQueueScheduler 抽象了 NSOperationQueue痰催。它具備 NSOperationQueue 的一些特點(diǎn),例如迎瞧,你可以通過(guò)設(shè)置 maxConcurrentOperationCount夸溶,來(lái)控制同時(shí)執(zhí)行并發(fā)任務(wù)的最大數(shù)量。

Error Handling - 錯(cuò)誤處理

RxSwift 主要有兩種錯(cuò)誤處理機(jī)制:

  • retry - 重試
  • catch - 恢復(fù)

retry - 重試

  • retry
let rxJson: Observable<JSON> = ...

rxJson
    .retry(3)
    .subscribe(onNext: { json in
        print("取得 JSON 成功: \(json)")
    }, onError: { error in
        print("取得 JSON 失敗: \(error)")
    })
    .disposed(by: disposeBag)

失敗后重試三次

  • retryWhen
    操作符凶硅,這個(gè)操作符主要描述應(yīng)該在何時(shí)重試缝裁,并且通過(guò)閉包里面返回的 Observable 來(lái)控制重試的時(shí)機(jī):
let maxRetryCount = 4       // 最多重試 4 次
let retryDelay: Double = 5  // 重試延時(shí) 5 秒

rxJson
    .retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
        return rxError.flatMapWithIndex { (error, index) -> Observable<Int> in
            guard index < maxRetryCount else {
                return Observable.error(error)
            }
            return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance)
        }
    }
    .subscribe(...)
    .disposed(by: disposeBag)

catchError - 恢復(fù)

  • catchError
    可以在錯(cuò)誤產(chǎn)生時(shí),用一個(gè)備用元素或者一組備用元素將錯(cuò)誤替換掉:
let rxData: Observable<Data> = ...      // 網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù)
let cahcedData: Observable<Data> = ...  // 之前本地緩存的數(shù)據(jù)

rxData
    .catchError { _ in cahcedData }
    .subscribe(onNext: { date in
        print("獲取數(shù)據(jù)成功: \(date.count)")
    })
    .disposed(by: disposeBag)
  • catchErrorJustReturn 當(dāng)錯(cuò)誤產(chǎn)生時(shí)足绅,就返回一個(gè)空數(shù)組压语,于是就會(huì)顯示一個(gè)空列表頁(yè)。

Result

展示錯(cuò)誤結(jié)果

updateUserInfoButton.rx.tap
    .withLatestFrom(rxUserInfo)
    .flatMapLatest { userInfo -> Observable<Result<Void>> in
        return update(userInfo)
            .map(Result.success)  // 轉(zhuǎn)換成 Result
            .catchError { error in Observable.just(Result.failure(error)) }
    }
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { result in
        switch result {           // 處理 Result
        case .success:
            print("用戶信息更新成功")
        case .failure(let error):
            print("用戶信息更新失敱嗉臁: \(error.localizedDescription)")
        }
    })
    .disposed(by: disposeBag)

其他

后面會(huì)講下具體實(shí)踐-UI上的使用胎食,還有更多理論性的東西就看文檔就ok了,操作符遇到了再查允懂。
基本常用控件
UITablView和UICollectionview使用
其他不常用控件
所有例子demo

參考文獻(xiàn)

swift開(kāi)發(fā)
RxSwift中文文檔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厕怜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蕾总,更是在濱河造成了極大的恐慌粥航,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件生百,死亡現(xiàn)場(chǎng)離奇詭異递雀,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)蚀浆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門缀程,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)搜吧,“玉大人,你說(shuō)我怎么就攤上這事杨凑÷四危” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵撩满,是天一觀的道長(zhǎng)蜒程。 經(jīng)常有香客問(wèn)我,道長(zhǎng)伺帘,這世上最難降的妖魔是什么昭躺? 我笑而不...
    開(kāi)封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮伪嫁,結(jié)果婚禮上窍仰,老公的妹妹穿的比我還像新娘。我一直安慰自己礼殊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布针史。 她就那樣靜靜地躺著晶伦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪啄枕。 梳的紋絲不亂的頭發(fā)上婚陪,一...
    開(kāi)封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音频祝,去河邊找鬼泌参。 笑死,一個(gè)胖子當(dāng)著我的面吹牛常空,可吹牛的內(nèi)容都是我干的沽一。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼漓糙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼铣缠!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起昆禽,我...
    開(kāi)封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蝗蛙,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后醉鳖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體捡硅,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年盗棵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壮韭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片北发。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泰涂,靈堂內(nèi)的尸體忽然破棺而出鲫竞,到底是詐尸還是另有隱情,我是刑警寧澤逼蒙,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布从绘,位于F島的核電站,受9級(jí)特大地震影響是牢,放射性物質(zhì)發(fā)生泄漏僵井。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一驳棱、第九天 我趴在偏房一處隱蔽的房頂上張望批什。 院中可真熱鬧,春花似錦社搅、人聲如沸驻债。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)合呐。三九已至,卻和暖如春笙以,著一層夾襖步出監(jiān)牢的瞬間淌实,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工猖腕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拆祈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓倘感,卻偏偏與公主長(zhǎng)得像放坏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子老玛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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

  • 概述 RxSwift顧名思義是Swift的一種框架轻姿,您或許曾經(jīng)聽(tīng)說(shuō)過(guò)「響應(yīng)式編程」(Reactive Progra...
    Mr大喵喵閱讀 1,869評(píng)論 3 4
  • 前言RxSwift的目的是讓數(shù)據(jù)/事件流和異步任務(wù)能夠更方便的序列化處理,能夠使用Swift進(jìn)行響應(yīng)式編程逻炊。 本文...
    努力奔跑的小男孩閱讀 1,880評(píng)論 0 3
  • 一互亮、Retrofit詳解 ·Retrofit的官網(wǎng)地址為 : http://square.github.io/re...
    余生_d630閱讀 1,858評(píng)論 0 5
  • 一、RxJava操作符概述 RxJava中的操作符就是為了提供函數(shù)式的特性余素,函數(shù)式最大的好處就是使得數(shù)據(jù)處理簡(jiǎn)潔易...
    無(wú)求_95dd閱讀 3,082評(píng)論 0 21
  • 引入依賴: implementation 'io.reactivex.rxjava2:rxandroid:2.0....
    為夢(mèng)想戰(zhàn)斗閱讀 1,303評(píng)論 0 0