RxSwift For Dummies ?? Part2

image.png

我們在上一篇文章中介紹了 RxSwift 基礎(chǔ)的部分. 現(xiàn)在我們來學(xué)習(xí)一些操作符, 來學(xué)習(xí)一下 FRP 中的F(unctional) 部分

Schedulers

我們先學(xué)習(xí)一下之前就已經(jīng)提到過的, 但是沒有詳細(xì)介紹的 Schedulers

Schedulers 最常見的用法就是告訴 Observables 和訂閱者 應(yīng)該在哪個線程或者隊列中發(fā)送事件,或者通知。

關(guān)于 Schedulers 最常見的操作符是observerOnsubscribleOn

通常情況下 Observables 會在它被訂閱的那個線程發(fā)送事件或者通知。

ObserveOn

ObserveOn 指定 Observables 發(fā)送事件的線程或者隊列。它不會改變它執(zhí)行的線程。

舉一個跟 part1 很相似的例子:

let observable = Observable<String>.create { (observer) -> Disposable in
    DispatchQueue.global(qos: .default).async {
        Thread.sleep(forTimeInterval: 10)
        DispatchQueue.main.async {
            observer.onNext("Hello dummy ??")
            observer.onCompleted()
        }
    }
    return Disposables.create()
}

假設(shè)訂閱者是一個 UI 層的東西, 比如說是一個 UIViewController 或者 UIView

DispatchQueue.global(qos: .default).async

我們把這個任務(wù)放在子線程中去執(zhí)行, 以免阻塞 UI

DispatchQueue.main.async{ ...

我們需要在主線程中去更新 UI, 你應(yīng)該知道 UIKit 要求對 UI 的操作都必須在主線程中進(jìn)行。所以這些操作對你來說一定是很熟悉的了。

記下來使用 ObserveOn 來重構(gòu)一下這段代碼

let observable = Observable<String>.create({ (observer) -> Disposable in
    DispatchQueue.global(qos: .default).async {
        Thread.sleep(forTimeInterval: 10)
        observer.onNext("Hello dummy ??")
        observer.onCompleted()
    }
        return Disposables.create()
    }).observeOn(MainScheduler.instance)

我們刪掉了 DispatchQueue.main.async {} 然后添加了 .observeOn(MainScheduler.instance)。 這個就可以讓所有的事件都在主線程中被發(fā)送出去。就是這么簡單。 "Hello dummy ??" 這個元素就能夠很安全的被發(fā)送給 UI 的元素, 因為我們可以很確定他會在主線程中被發(fā)送出去。

observable.subscribe(onNext: { [weak self] (element) in
    self?.label.text = element
}).addDisposableTo(disposeBag)

ObserveOn 大概是最常見的線程調(diào)度操作符了。你希望 Observables 包含了所有的邏輯, 和線程操作, 讓訂閱者盡可能的簡單。所以我們接下來再了解一下 subscribeOn 這個操作符。

SubscribeOn (Optional)

這是一個非常先進(jìn)的操作符。你可以先跳過這部分, 以后再來研究??

subscribeOnObserveOn 非常的相似。但是他只能改變 Observable 將要執(zhí)行的任務(wù)所在的線程。

let observable = Observable<String>.create { (observer) -> Disposable in
    Thread.sleep(forTimeInterval: 10)
    observer.onNext("Hello dummy ??")
    observer.onCompleted()
    return Disposables.create()
} 
observable
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .default))
    .subscribe(onNext: { [weak self] (element) in
        self?.label.text = element
    }).addDisposableTo(disposeBag)

上面的代碼中, 我刪掉了 Observable 中的 DispatchQueue.global(qos: .default).async {} 是這個訂閱者告訴他應(yīng)該在一個 global queue 中執(zhí)行下面的操作, 以免阻塞 UI. 很明顯這回導(dǎo)致一個異常的拋出, 之前提到過: 這回導(dǎo)致 Observable 在全局隊列中執(zhí)行, 也會在全局隊列中發(fā)出事件。只需要添加在 Observable 中添加 .observeOn(MainScheduler.instance)就能避免這個問題。

let observable = Observable<String>.create { (observer) -> Disposable in
    Thread.sleep(forTimeInterval: 10)
    observer.onNext("Hello dummy ??")
    observer.onCompleted()
        return Disposables.create()
}.observeOn(MainScheduler.instance)      
observable
    .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .default))
    .subscribe(onNext: { [weak self] (element) in
        self?.label.text = element
    }).addDisposableTo(disposeBag)

添加之后,就能夠發(fā)現(xiàn)剛剛說到的問題已經(jīng)解決掉了。

我們什么時候應(yīng)該用 observeOn 呢?最常見的場景是:如果在 Observable 不需要在后臺執(zhí)行耗時操作(讀取數(shù)據(jù), 大的計算任務(wù))的話.我不認(rèn)為這是非常頻繁的事情。但是,come on! 多知道一個你能用的工具 ??不是件很 cool 的事情嗎?

Scheduler Types

做為 RxSwift 菜鳥, 好奇 observeOnMainScheduler.instance 沒什么關(guān)系。你可以自己創(chuàng)建一個線程或者直接使用已經(jīng)創(chuàng)建好了的。如果你很好奇的話這里有很多。 這也沒什么好復(fù)雜的, 就是對 GCD 和 NSOperation 的封裝而已。

Transforming Operators

現(xiàn)在你已經(jīng)知道兩種操作符了: 創(chuàng)建操作符(createinterval、just) 和 功能操作符(observeOn, subscribeOn)。 現(xiàn)在再學(xué)一些轉(zhuǎn)換操作符吧!

Map

這是非常簡單,但非常有用的操作符。它也可能是你未來最常用的一個操作符號。

let observerable = Observable<Int>.create { (observer) -> Disposable in
    observer.onNext(1)
    return Disposables.create()
}        
let boolObservable: Observable<Bool> = observerable.map{(element) -> Bool in
    if element == 0 {
        return false
    }
    return true
}
boolObservable.subscribe(onNext: { (boolElement) in
    print(boolElement)
}).addDisposableTo(disposeBag)

Map 操作符號,改變了序列中值的類型。他映射了一個 Observable 所以他以你告訴他的新的方式發(fā)送事件。在這個例子中, 我們將一個 Int 類型的 Observable 映射成了一個 Bool 類型。

所以這個例子的結(jié)果是

true

Scan

scan 要復(fù)雜一些了。

let observable = Observable<String>.create { (observer) -> Disposable in
    observer.onNext("D")
    observer.onNext("U")
    observer.onNext("M")
    observer.onNext("M")
    observer.onNext("Y")
    return Disposables.create()
}
observable.scan("") { (lastValue, currentValue) -> String in
    return lastValue + currentValue
}.subscribe(onNext: { (element) in
    print(element)
}).addDisposableTo(disposeBag)

在這個例子中會輸出

D
DU
DUM
DUMM
DUMMY

scan操作符, 讓你可以通過上一個值來改變這一個值。他也被稱作元素堆積。上面代碼中的 “”是掃描參數(shù)傳遞的起始值。還是想著能干什么呢?

let observable = Observable<Int>.create { (observer) -> Disposable in
    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)
    observer.onNext(4)
    observer.onNext(5)
    return Disposables.create()
}
observable.scan(1) { (lastValue, currentValue) -> Int in
    return lastValue + currentValue
}.subscribe(onNext: { (element) in
    print(element)
}).addDisposableTo(disposeBag)

這是通過 scan 操作符計算 5 的階層。 算出來的答案是: 120

Marin 給了一個更有用的例子 關(guān)于按鈕的 selected 狀態(tài)

let button = UIButton()
button.rx.tap.scan(false) { last, new in
    return !last
}.subscribe(onNext: { (element) in
    print("tap: \(element)")
}).addDisposableTo(disposeBag)

現(xiàn)在你知道他能干什么了吧? 當(dāng)然還有很多其他的轉(zhuǎn)換操作符。

Filtering Operators

發(fā)出事件是很重要的事情, 但是很多情況下我們還需要過濾掉一些沒用的事件。這就是 filter 操作符所做的事什么。

Filter

決定那些事件是要響應(yīng)的那些是要過濾掉的。

let observerable = Observable<String>.create { (observer) -> Disposable in
    observer.onNext("??")
    observer.onNext("??")
    observer.onNext("??")
    observer.onNext("??")
    observer.onNext("??")
    return Disposables.create()
}
observerable.filter { (element) -> Bool in
    return element == "??"
}.subscribe(onNext: { (element) in
    print(element)
}).addDisposableTo(disposeBag)

輸出

??
??

Debounce

簡單且有用

observerable
    .debounce(2, scheduler: MainScheduler.instance)
    .subscribe(onNext: { (element) in
        print(element)
    }).addDisposableTo(disposeBag)

debounce 會過濾掉2秒以內(nèi)的所有事件, 如果事件a在上一次事件之后的0.5秒被發(fā)送出來。那么他就會被過濾掉。如果他在上次事件的2.5秒被發(fā)送出來。那么他就會被接受到。需要注意的是, 如果就算當(dāng)前時間之后沒有其他的事件,他也要在2秒之后被發(fā)送出來。

譯者: 需要注意的 debouncethrottle 的區(qū)別。還有 Obj-C 中的 ReactiveCocoa 中的 throttle 的區(qū)別。

Combining Operator

聯(lián)合操作符讓你可以把多個 Observable 轉(zhuǎn)換成一個。

Merge

合并只是將多個 Observable 發(fā)送的事件合并到一個 Observable 中。

let observable = Observable<String>.create { (observer) -> Disposable in
    observer.onNext("??")
    observer.onNext("??")
    return Disposables.create()
}
let observable2 = Observable<String>.create { (observer) -> Disposable in
    observer.onNext("??")
    observer.onNext("??")
    return Disposables.create()
}
Observable.of(observable, observable2).merge().subscribe(onNext: { (element) in
    print(element)
}).addDisposableTo(disposeBag)     

??
??
??
??

Zip

Zip 將每個 Observable 發(fā)出來的值合并成一個值。

let observable = Observable<String>.create { (observer) -> Disposable in
    observer.onNext("??")
    observer.onNext("??")
    return Disposables.create()
}
let observable2 = Observable<String>.create { (observer) -> Disposable in
    observer.onNext("??")
    observer.onNext("??")
    return Disposables.create()
}
Observable.zip(observable ,observable2).subscribe(onNext: { (element) in
    print(element)
}).addDisposableTo(disposeBag)

????
????

這是一個很有用的操作符。還是舉一個例子吧! 假如你有兩個網(wǎng)絡(luò)請求, 你需要等到他們都結(jié)束之后再進(jìn)行下一步操作。

let observable = Observable<String>.create { (observer) -> Disposable in
    DispatchQueue.main.async {
        Thread.sleep(forTimeInterval: 3)
        observer.onNext("fetched from sever 1")
    }
    return Disposables.create()
}
let observable2 = Observable<String>.create { (observer) -> Disposable in
    DispatchQueue.main.async {
        Thread.sleep(forTimeInterval: 2)
        observer.onNext("fetched from sever 2")
    }
    return Disposables.create()
}
Observable.zip(observable, observable2)
    .subscribe(onNext: { (element) in
        print(element)
    }).addDisposableTo(disposeBag)

Zip 會等到兩個 Observable 都結(jié)束之后將兩個請求的結(jié)果合并成一個值發(fā)送出來。

Other Operators

還有很多有趣的操作符, 比如 reduce、 takeUntil 等等。我認(rèn)為如果你什么時候有了一些想法, 你也會很容易的找到他們。他們非常的強(qiáng)大, 能讓你快速簡單的操作事件序列。

Mixing Operators

這個教程不需要具體的實例項目, 但是能快的將各種操作符搭配使用。我們來做一個實驗吧:工具根據(jù)事件改變視圖的顏色。

Observable<NSDate>.create { (observer) -> Disposable in
    DispatchQueue.global(qos: .default).async {
        while true {
            Thread.sleep(forTimeInterval: 0.01)
            observer.onNext(NSDate())
        }
    }
    return Disposables.create()
    }// 需要在主線程中刷新 UI
    .observeOn(MainScheduler.instance)
    // 我們只需要能夠被2整除的事件
    .filter { (date) -> Bool in
        return Int(date.timeIntervalSince1970) % 2 == 0
    }
    // 將數(shù)據(jù)轉(zhuǎn)換成顏色
    .map { (date) -> UIColor in
        let interval: Int = Int(date.timeIntervalSince1970)
        let color1 = CGFloat( Double(((interval * 1) % 255)) / 255.0)
        let color2 = CGFloat( Double(((interval * 2) % 255)) / 255.0)
        let color3 = CGFloat( Double(((interval * 3) % 255)) / 255.0)
        return UIColor(red: color1, green: color2, blue: color3, alpha: 1)
    }
    .subscribe(onNext: {[weak self] (color) in
        self?.demoView.backgroundColor = color
    }).addDisposableTo(disposeBag)

You can find more examples in the RxSwfit playgrounds

That's it!

你知道了太多了。剩下的就是 Subjects

原文地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位,與響應(yīng)式編程作為結(jié)合使用的,對什么是操作、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,987評論 0 10
  • 作者寄語 很久之前就想寫一個專題,專寫Android開發(fā)框架,專題的名字叫 XXX 從入門到放棄 ,沉淀了這么久,...
    戴定康閱讀 7,735評論 13 85
  • http://blog.csdn.net/yyh352091626/article/details/5330472...
    奈何心善閱讀 3,651評論 0 0
  • 參考:給 Android 開發(fā)者的 RxJava 詳解-扔物線深入淺出RxJava 基礎(chǔ) "a library f...
    Vincen1024閱讀 579評論 0 1
  • 我從去年開始使用 RxJava ,到現(xiàn)在一年多了。今年加入了 Flipboard 后,看到 Flipboard 的...
    Jason_andy閱讀 5,763評論 7 62

友情鏈接更多精彩內(nèi)容