RxSwift For Dummies ?? Part3

image.png

好了, 接下來是第三個部分。Subjects

學(xué)了之前內(nèi)容. 我們可能已經(jīng)發(fā)現(xiàn)了。之前學(xué)習(xí)的內(nèi)容都是 Observables 輸出事件的部分。我們可以訂閱他, 就能知道他輸出的事件了。但是我們還不能改變他。

Subject 也是一個 Observable 但是他是能夠同時輸入和輸出的。也就是說, 我們可以動態(tài)(強制)的在一個序列中發(fā)出信號。

        let subject = PublishSubject<String>()
        // 可以直接轉(zhuǎn)換,因為他也是一個 `Observable`
        let observable: Observable<String> = subject
        observable.subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)
        // 只要你想發(fā)出一個新的事件, 就可以用 onNext 方法 
        subject.onNext("Hey!")
        subject.onNext("I'm back!")

onNext 是一個輸出事件的方法。最后控制臺會輸出

"Hey!"
"I'm back!"

Subject 到底有什么用呢? 為了很輕松的將 Rxswift 中聲明式的世界和我們平常的世界連接起來。讓我們在需要寫實現(xiàn)式的代碼的時候更 Rx

在一個純正的 Rx 的世界里。當(dāng)你需要有一個更完美的流的時候, 不用去管這個 Observable 是怎么實現(xiàn)的。這個東西我會另外的解釋。反正, 如果你需要, 大膽的用吧。

上面式關(guān)于 Subject 最基本的內(nèi)容。接下來我們學(xué)習(xí)一下怎么更好的使用 Subject

Hot?? vs Cold??

在第一篇文章中就已經(jīng)提到過了熱信號??和冷信號??。今天我們在深入的了解一點吧,因為 Subject 實際上是我們第一次接觸到真正的熱信號。

我們一定確定了,當(dāng)我們使用 create 創(chuàng)建一個 Observable 的時候, 由于沒有人訂閱他,所以她是不會發(fā)送消息的。只有被 subscribe(訂閱)之后才會開始發(fā)送消息出來。這就是我們叫它為冷信號??的原因。如果很不幸你忘了這個知識點。你可以回到第一篇文章去看看。熱信號?? 就是那種即使沒有被訂閱也會發(fā)出消息的信號, 這也是 subject 做的事情。

        let subject = PublishSubject<String>()
        let observable: Observable<String> = subject
        // 這個信號還沒有被訂閱, 所以這個值不回被接受到
        subject.onNext("Am I too early for the party?")
        
        observable
            .subscribe(onNext: { (text) in
                print(text)
            }).addDisposableTo(disposeBag)
        // 這個值發(fā)出來的時候已經(jīng)有一個訂閱者了, 所以這個值會打印出來
        subject.onNext("??????")

很簡單直接吧。如果在第一篇中你理解了冷信號的話, 理解熱信號也是很自然的事情。

Subject Types

常用的 Subject 有三種。 他們其實都差不多, 唯一的區(qū)別就是: 在訂閱之前, 它會干什么。

Publish Subject

在上面的例子中已經(jīng)說到了。 PublishSubject 會忽略掉在訂閱之前發(fā)出來的信號。

        let subject = PublishSubject<String>()
        let observable: Observable<String> = subject
        subject.onNext("Ignored...")
        observable.subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)
        subject.onNext("Printed!")

當(dāng)你只關(guān)注你訂閱之后發(fā)生了什么的時候, 就可以使用 PublishSubject

Replay Subjects

ReplaySubject 會將最后 n 個值發(fā)出來, 即使是訂閱發(fā)生之前的值。 這個 n 個值被被放在一個環(huán)從區(qū)里面。在這個例子中會緩有 3 個值被保留。

        let subject = ReplaySubject<String>.create(bufferSize: 3)
        let observable: Observable<String> = subject

        subject.onNext("Not printed!")
        subject.onNext("Printed")
        subject.onNext("Printed!")
        subject.onNext("Printed!")
        
        observable.subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)
        subject .onNext("Printed!")

當(dāng)我們需要知道訂閱之前發(fā)生了什么的時候, 我們就需要使用 ReplaySubject 了。

Behavior Subject

BehaviorSubject 只會重復(fù)最后一個值。 更其他的 Subject 的同, 他在創(chuàng)建的時候就需要給定一個初始值。

        let subject = BehaviorSubject<String>(value: "Initial value")
        let observable: Observable<String> = subject
        
        subject.onNext("Not printed!")
        subject.onNext("Not printed!")
        subject.onNext("Printed!")
        
        observable.subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)
        subject.onNext("Printed!")

當(dāng)你只需要知道最后一個值的時候。就需要使用 BehaviorSubject

Binding

你可以把一個 ObservableSubject 綁定到一起。也就是說可以讓這個 Observable 將它的序列里的所有值都發(fā)送給這個 Subject

        let subject = PublishSubject<String>()
        let observable = Observable<String>.just("I'm being passed around ??")
        subject.subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)
        
        observable.subscribe { (event) in
            subject.on(event)
        }.addDisposableTo(disposeBag)

有一個語法糖來簡化這些代碼。

        let subject = PublishSubject<String>()
        let observable = Observable<String>.just("I'm being passed around ??")
        subject.subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)
        
        observable.bind(to: subject).addDisposableTo(disposeBag)

輸出

I'm being passed around ??

Warning

Binding 不僅僅會傳遞值, 他也會把完成和錯誤都傳遞過來。這種情況下這個 Subject 就會被釋放。

Quick Example

還是把第一篇文章中的 Demo 稍微修改一下吧。

import Foundation
import RxCocoa
import RxSwift

final class GoogleModel {
    let googleString = BehaviorSubject<String>(value: "")
    private let disposeBag = DisposeBag()
    
    
    func fetchNetString()  {
        let observable = Observable<String>.create { (observer) -> Disposable in
            let session = URLSession.shared
            let task = session.dataTask(with: URL(string: "https://www.google.com")!, completionHandler: { (data, response, error) in
                
                DispatchQueue.main.async {
                    if let err = error {
                        observer.onError(err)
                    } else {
                        let googleString = NSString(data: data!, encoding: 1) as String?
                        
                        observer.onNext(googleString!)
                        observer.onCompleted()
                    }
                }
            })
            task.resume()
            return Disposables.create{
                task.cancel()
            }
        }
        
        // Bind the observable to the subject
        observable.bind(to: googleString).addDisposableTo(disposeBag)
    }
}        
// Bind the observable to the subject
observable.bind(to: googleString).addDisposableTo(disposeBag)

可以看到,在這個例子中,我們有一個視圖模型將 googleString 這個 subject 暴露出來。讓 ViewController 能夠訂閱。我們將這個 observable 綁定到這個 subject 上, 這樣我們就可以在網(wǎng)絡(luò)請求有結(jié)果的時候, 立馬將請求結(jié)果傳遞到這給 subject

Bonus: Variable

距離完完全全的 Rx 還差最后一點了。強行的獲取之前發(fā)送出來的值。

這就是為什么會有 Variable 這個東西了。Variable 是對 BehaviorSubject 的簡單包裝。可以看一下 它的實現(xiàn)是非常簡單的。但它卻非常的方便。

還是用一個小例子來說明這個問題吧。在這個例子中, 我們需要在任何時間都可以得到 "googleString" "當(dāng)前" 的值。

        let googleString = Variable("currentString")
        // get
        print(googleString.value)
        // set
        googleString.value = "newString"
        // 訂閱
        googleString.asObservable().subscribe(onNext: { (text) in
            print(text)
        }).addDisposableTo(disposeBag)

你一定會愛上他的。這基本上就是 RxSwift 的簡單模式了。

看起來很簡單吧,但是別忘了,還是有很多的坑的。還是小心為上。下一篇文章我會講講: 怎么寫 Rxswift 最保險。

That's it!

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

原文地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,703評論 2 380

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