RxSwift - 學(xué)習(xí)筆記一

一、創(chuàng)建可觀察者

//
//  ObservableTestVC.swift
//  BasicSwiftDemo
//
//  Created by Pro on 2020/11/11.
//  Copyright ? 2020 com.liufeng.mysterFeng. All rights reserved.
//

import UIKit
enum MyError: Error {
    case A
    case B
}
let disposeBag = DisposeBag()


class ObservableTestVC: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // 我們可以通過如下幾種方法來創(chuàng)建一個 Observable 序列
        
        //傳入默認(rèn)值初始化
        let observable1 = Observable<Int>.just(5)
        observable1.subscribe {
            print($0)
        }.disposed(by: disposeBag)
        
        //必須同類型
        let observable2 = Observable.of("A", "B", "C")
        observable2.subscribe {
            print($0)
        }.disposed(by: disposeBag)
        
        //傳入數(shù)組
        let observable3 = Observable.from(["A", "B", "C"])
        observable3.subscribe{
         print($0)
        }.disposed(by: disposeBag)
        //創(chuàng)建空內(nèi)容序列
        let observable4 = Observable<Int>.empty()
        observable4.subscribe{
         print($0)
        }.disposed(by: disposeBag)

        //永遠不終止也不發(fā)出event
        let observable5 = Observable<Int>.never()
        observable5.subscribe{
         print($0)
        }.disposed(by: disposeBag)

        //不做任何操作直接發(fā)出一個錯誤
        let observable6 = Observable<Int>.error(MyError.A)
        observable6.subscribe{
         print($0)
        }.disposed(by: disposeBag)

        //創(chuàng)建一個范圍w數(shù)值序列
        let observable7 = Observable.range(start: 1, count: 5)
        observable7.subscribe{
         print($0)
        }.disposed(by: disposeBag)

        //無限發(fā)出event永不終止
        let observable8 = Observable.repeatElement(1)
        observable8.subscribe{
         print($0)
        }.disposed(by: disposeBag)

        //滿足所有條件發(fā)出 初始值是0 必須小于等于10 每次加2
        let observable9 = Observable.generate(
            initialState: 0,
            condition: { $0 <= 10 },
            iterate: { $0 + 2 }
        )
        observable9.subscribe{
         print($0)
        }.disposed(by: disposeBag)

        
        //這個block有一個回調(diào)參數(shù)observer就是訂閱這個Observable對象的訂閱者
        let observable10 = Observable<String>.create{observer in
            observer.onNext("啊啊啊啊啊啊啊")
            observer.onCompleted()
            return Disposables.create()
        }
        
        //訂閱測試
        observable10.subscribe {
            print($0)
        }.disposed(by: disposeBag)
        
        //用于標(biāo)記是奇數(shù)、還是偶數(shù)
        var isOdd = true
        
        //使用deferred()方法延遲Observable序列的初始化,通過傳入的block來實現(xiàn)Observable序列的初始化并且返回。
        let factory : Observable<Int> = Observable.deferred {
            
            //讓每次執(zhí)行這個block時候都會讓奇、偶數(shù)進行交替
            isOdd = !isOdd
            
            //根據(jù)isOdd參數(shù),決定創(chuàng)建并返回的是奇數(shù)Observable、還是偶數(shù)Observable
            if isOdd {
            return Observable.of(1, 3, 5 ,7)
            }else {
                return Observable.of(2, 4, 6, 8)
            }
        }
        
        //第1次訂閱測試
        factory.subscribe { event in
            print("\(isOdd)", event)
        }.disposed(by: disposeBag)
        
        //第2次訂閱測試
        factory.subscribe { event in
            print("\(isOdd)", event)
        }.disposed(by: disposeBag)
        
        

        //定時器
        
        let observable12 = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        observable12.subscribe { event in
            print(event)
        }.disposed(by: disposeBag)
        
        
        //5秒種后發(fā)出唯一的一個元素0
        let observable13 = Observable<Int>.timer(5, scheduler: MainScheduler.instance)
        observable13.subscribe { event in
            print(event)
        }.disposed(by: disposeBag)
        
        
        //延時5秒種后,每隔1秒鐘發(fā)出一個元素
        let observable14 = Observable<Int>.timer(5, period: 1, scheduler: MainScheduler.instance)
        observable14.subscribe { event in
            print(event)
        }.disposed(by: disposeBag)
        
        _ = Observable<Int>.timer(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance)

        
    }
    

}

二、訂閱觀察者

RxSwift 還提供了另一個 subscribe 方法,它可以把 event 進行分類

  • 通過不同的 block 回調(diào)處理不同類型的 event
  • 同時會把 event 攜帶的數(shù)據(jù)直接解包出來作為參數(shù),方便我們使用。
  • 所以我們也可以只處理 onNext 而不管其他的情況
let observable = Observable.of("A", "B", "C")
         
observable.subscribe(onNext: { element in
    print(element)
}, onError: { error in
    print(error)
}, onCompleted: {
    print("completed")
}, onDisposed: {
    print("disposed")
})

三、監(jiān)聽事件doOn

let observable = Observable.of("A", "B", "C")
 
observable
    .do(onNext: { element in
        print("Intercepted Next:", element)
    }, onError: { error in
        print("Intercepted Error:", error)
    }, onCompleted: {
        print("Intercepted Completed")
    }, onDispose: {
        print("Intercepted Disposed")
    })
    .subscribe(onNext: { element in
        print(element)
    }, onError: { error in
        print(error)
    }, onCompleted: {
        print("completed")
    }, onDisposed: {
        print("disposed")
    })

四. 觀察者(Observer)

觀察者(Observer)的作用就是監(jiān)聽事件,然后對這個事件做出響應(yīng)?;蛘哒f任何響應(yīng)事件的行為都是觀察者。

  • 觀察者就是由 onNext,onError,onCompleted 這些閉包構(gòu)建
  • 在 bind 方法中創(chuàng)建
        //Observable序列(每隔1秒鐘發(fā)出一個索引數(shù))
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
 
        observable
            .map { "當(dāng)前索引數(shù):\($0 )"}
            .bind { [weak self](text) in
                //收到發(fā)出的索引數(shù)后顯示到label上
                self?.label.text = text
            }
            .disposed(by: disposeBag)
  
  • AnyObserver 創(chuàng)建觀察者
//觀察者
let observer: AnyObserver<String> = AnyObserver { (event) in
    switch event {
    case .next(let data):
        print(data)
    case .error(let error):
        print(error)
    case .completed:
        print("completed")
    }
}
 
let observable = Observable.of("A", "B", "C")
observable.subscribe(observer)

  • 配合 bindTo 方法使用
        
        //觀察者
        let observer: AnyObserver<String> = AnyObserver { [weak self] (event) in
            switch event {
            case .next(let text):
                //收到發(fā)出的索引數(shù)后顯示到label上
                self?.label.text = text
            default:
                break
            }
        }
         
        //Observable序列(每隔1秒鐘發(fā)出一個索引數(shù))
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        observable
            .map { "當(dāng)前索引數(shù):\($0 )"}
            .bind(to: observer)
            .disposed(by: disposeBag)
  
  • 使用 Binder 創(chuàng)建觀察者
    Binder 主要有以下兩個特征:

1.不會處理錯誤事件
2.確保綁定都是在給定 Scheduler 上執(zhí)行(默認(rèn) MainScheduler)

//觀察者
        let observer: Binder<String> = Binder(label) { (view, text) in
            //收到發(fā)出的索引數(shù)后顯示到label上
            view.text = text
        }
         
        //Observable序列(每隔1秒鐘發(fā)出一個索引數(shù))
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        observable
            .map { "當(dāng)前索引數(shù):\($0 )"}
            .bind(to: observer)
            .disposed(by: disposeBag)
    }

Binder 在 RxCocoa 中的應(yīng)用

extension Reactive where Base: UIControl {
     
    /// Bindable sink for `enabled` property.
    public var isEnabled: Binder<Bool> {
        return Binder(self.base) { control, value in
            control.isEnabled = value
        }
    }
}

let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
    .map { $0 % 2 == 0 }
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

五、自定義可綁定屬性

1.對UI控件自定義

extension UILabel {
    public var fontSize: Binder<CGFloat> {
        return Binder(self) { label, fontSize in
            label.font = UIFont.systemFont(ofSize: fontSize)
        }
    }
}

2.通過對 Reactive 類進行擴展

extension Reactive where Base: UILabel {
    public var fontSize: Binder<CGFloat> {
        return Binder(self.base) { label, fontSize in
            label.font = UIFont.systemFont(ofSize: fontSize)
        }
    }
}

RxSwift 已經(jīng)為我們提供許多常用的可綁定屬性,自己閱讀即可

六、Subjects 介紹

當(dāng)我們創(chuàng)建一個 Observable 的時候就要預(yù)先將要發(fā)出的數(shù)據(jù)都準(zhǔn)備好,等到有人訂閱它時再將數(shù)據(jù)通過 Event 發(fā)出去。
但有時我們希望 Observable 在運行時能動態(tài)地“獲得”或者說“產(chǎn)生”出一個新的數(shù)據(jù),再通過 Event 發(fā)送出去。比如:訂閱一個輸入框的輸入內(nèi)容,當(dāng)用戶每輸入一個字后,這個輸入框關(guān)聯(lián)的 Observable 就會發(fā)出一個帶有輸入內(nèi)容的 Event,通知給所有訂閱者

Subjects 既是訂閱者,也是 Observable

  • 說它是訂閱者,是因為它能夠動態(tài)地接收新的值
  • 說它又是一個 Observable,是因為當(dāng) Subjects 有了新的值之后,就會通過 Event 將新值發(fā)出給他的所有訂閱者

Subject 常用的幾個方法

onNext(:):是 on(.next(:)) 的簡便寫法。該方法相當(dāng)于 subject 接收到一個 .next 事件。
onError(:):是 on(.error(:)) 的簡便寫法。該方法相當(dāng)于 subject 接收到一個 .error 事件。
onCompleted():是 on(.completed) 的簡便寫法。該方法相當(dāng)于 subject 接收到一個 .completed 事件

一共有四種 Subjects

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject
  • Variable

七、變換操作

  • buffer

buffer 方法作用是緩沖組合,第一個參數(shù)是緩沖時間,第二個參數(shù)是緩沖個數(shù),第三個參數(shù)是線程。

  • window

window 操作符和 buffer 十分相似。不過 buffer 是周期性的將緩存的元素集合發(fā)送出來,而 window 周期性的將元素集合以 Observable 的形態(tài)發(fā)送出來。

  • map

該操作符通過傳入一個函數(shù)閉包把原來的 Observable 序列轉(zhuǎn)變?yōu)橐粋€新的 Observable 序列。

  • flatMap

map 在做轉(zhuǎn)換的時候容易出現(xiàn)“升維”的情況。即轉(zhuǎn)變之后,從一個序列變成了一個序列的序列。
而 flatMap 操作符會對源 Observable 的每一個元素應(yīng)用一個轉(zhuǎn)換方法,將他們轉(zhuǎn)換成 Observables。 然后將這些 Observables 的元素合并之后再發(fā)送出來。即又將其 "拍扁"(降維)成一個 Observable 序列。
這個操作符是非常有用的。比如當(dāng) Observable 的元素本生擁有其他的 Observable 時,我們可以將所有子 Observables 的元素發(fā)送出來

  • flatMapLatest

flatMapLatest 與 flatMap 的唯一區(qū)別是:flatMapLatest 只會接收最新的 value 事件。

  • flatMapFirst

flatMapFirst 與 flatMapLatest 正好相反:flatMapFirst 只會接收最初的 value 事件。

  • concatMap

concatMap 與 flatMap 的唯一區(qū)別是:當(dāng)前一個 Observable 元素發(fā)送完畢后,后一個Observable 才可以開始發(fā)出元素?;蛘哒f等待前一個 Observable 產(chǎn)生完成事件后,才對后一個 Observable 進行訂閱。

  • scan

scan 就是先給一個初始化的數(shù),然后不斷的拿前一個結(jié)果和最新的值進行處理操作。

  • groupBy

groupBy 操作符將源 Observable 分解為多個子 Observable,然后將這些子 Observable 發(fā)送出來。
也就是說該操作符會將元素通過某個鍵進行分組,然后將分組后的元素序列以 Observable 的形態(tài)發(fā)送出來。

  • filter

該操作符就是用來過濾掉某些不符合要求的事件。

  • take

該方法實現(xiàn)僅發(fā)送 Observable 序列中的前 n 個事件,在滿足數(shù)量之后會自動 .completed。

  • skip

該方法用于跳過源 Observable 序列發(fā)出的前 n 個事件。

  • distinctUntilChanged

該操作符用于過濾掉連續(xù)重復(fù)的事件。

  • single

限制只發(fā)送一次事件,或者滿足條件的第一個事件。
如果存在有多個事件或者沒有事件都會發(fā)出一個 error 事件。
如果只有一個事件,則不會發(fā)出 error 事件。

  • elementAt

該方法實現(xiàn)只處理在指定位置的事件。

  • ignoreElements

該操作符可以忽略掉所有的元素,只發(fā)出 error 或 completed 事件。
如果我們并不關(guān)心 Observable 的任何元素,只想知道 Observable 在什么時候終止,那就可以使用 ignoreElements 操作符。

  • takeLast

該方法實現(xiàn)僅發(fā)送 Observable 序列中的后 n 個事件。

  • Sample

Sample 除了訂閱源 Observable 外,還可以監(jiān)視另外一個 Observable, 即 notifier 。
每當(dāng)收到 notifier 事件,就會從源序列取一個最新的事件并發(fā)送。而如果兩次 notifier 事件之間沒有源序列的事件,則不發(fā)送值。

  • debounce

debounce 操作符可以用來過濾掉高頻產(chǎn)生的元素,它只會發(fā)出這種元素:該元素產(chǎn)生后,一段時間內(nèi)沒有新元素產(chǎn)生。
換句話說就是,隊列中的元素如果和下一個元素的間隔小于了指定的時間間隔,那么這個元素將被過濾掉。
debounce 常用在用戶輸入的時候,不需要每個字母敲進去都發(fā)送一個事件,而是稍等一下取最后一個事件。

  • amb

當(dāng)傳入多個 Observables 到 amb 操作符時,它將取第一個發(fā)出元素或產(chǎn)生事件的 Observable,然后只發(fā)出它的元素。并忽略掉其他的 Observables。

  • takeWhile

該方法依次判斷 Observable 序列的每一個值是否滿足給定的條件。 當(dāng)?shù)谝粋€不滿足條件的值出現(xiàn)時,它便自動完成。

  • takeUntil

除了訂閱源 Observable 外,通過 takeUntil 方法我們還可以監(jiān)視另外一個 Observable, 即 notifier。
如果 notifier 發(fā)出值或 complete 通知,那么源 Observable 便自動完成,停止發(fā)送事件。

  • skipWhile

該方法用于跳過前面所有滿足條件的事件。
一旦遇到不滿足條件的事件,之后就不會再跳過了

  • skipUntil

同上面的 takeUntil 一樣,skipUntil 除了訂閱源 Observable 外,通過 skipUntil 方法我們還可以監(jiān)視另外一個 Observable, 即 notifier 。
與 takeUntil 相反的是。源 Observable 序列事件默認(rèn)會一直跳過,直到 notifier 發(fā)出值或 complete 通知。

  • startWith

該方法會在 Observable 序列開始之前插入一些事件元素。即發(fā)出事件消息之前,會先發(fā)出這些預(yù)先插入的事件消息。

  • merge

該方法可以將多個(兩個或兩個以上的)Observable 序列合并成一個 Observable 序列

  • zip

該方法可以將多個(兩個或兩個以上的)Observable 序列壓縮成一個 Observable 序列。
而且它會等到每個 Observable 事件一一對應(yīng)地湊齊之后再合并。
比如我們想同時發(fā)送兩個請求,只有當(dāng)兩個請求都成功后,再將兩者的結(jié)果整合起來繼續(xù)往下處理。這個功能就可以通過 zip 來實現(xiàn)。

//第一個請求
let userRequest: Observable<User> = API.getUser("me")
 
//第二個請求
let friendsRequest: Observable<Friends> = API.getFriends("me")
 
//將兩個請求合并處理
Observable.zip(userRequest, friendsRequest) {
        user, friends in
        //將兩個信號合并成一個信號,并壓縮成一個元組返回(兩個信號均成功)
        return (user, friends)
    }
    .observeOn(MainScheduler.instance) //加這個是應(yīng)為請求在后臺線程,下面的綁定在前臺線程。
    .subscribe(onNext: { (user, friends) in
        //將數(shù)據(jù)綁定到界面上
        //.......
    })
    .disposed(by: disposeBag)

  • combineLatest

該方法同樣是將多個(兩個或兩個以上的)Observable 序列元素進行合并。
但與 zip 不同的是,每當(dāng)任意一個 Observable 有新的事件發(fā)出時,它會將每個 Observable 序列的最新的一個事件元素進行合并

  • withLatestFrom

該方法將兩個 Observable 序列合并為一個。每當(dāng) self 隊列發(fā)射一個元素時,便從第二個序列中取出最新的一個值

  • switchLatest

switchLatest 有點像其他語言的 switch 方法,可以對事件流進行轉(zhuǎn)換。
比如本來監(jiān)聽的 subject1,我可以通過更改 variable 里面的 value 更換事件源。變成監(jiān)聽 subject2。

  • toArray

該操作符先把一個序列轉(zhuǎn)成一個數(shù)組,并作為一個單一的事件發(fā)送,然后結(jié)束。

  • reduce

reduce 接受一個初始值,和一個操作符號。
reduce 將給定的初始值,與序列里的每個值進行累計運算。得到一個最終結(jié)果,并將其作為單個值發(fā)送出去。

  • concat

concat 會把多個 Observable 序列合并(串聯(lián))為一個 Observable 序列。
并且只有當(dāng)前面一個 Observable 序列發(fā)出了 completed 事件,才會開始發(fā)送下一個 Observable 序列事件

?著作權(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)容

  • 最近在學(xué)習(xí)RxSwift相關(guān)的內(nèi)容,在這里記錄一些基本的知識點,以便今后查閱。 Observable 在RxSwi...
    L_Zephyr閱讀 1,897評論 1 4
  • 以下是自己學(xué)習(xí)的一些簡要記錄 1.Disposing:變量所占用的內(nèi)存空間釋放掉(手動釋放) 2.Dispose ...
    嘿_咱老地方見閱讀 623評論 0 0
  • RxSwift 使用詳解系列 Rx Rx是ReactiveX的縮寫,簡單來說就是基于異步事件序列的響應(yīng)式編程。Rx...
    內(nèi)心強大的Jim閱讀 989評論 0 0
  • 漸變的面目拼圖要我怎么拼? 我是疲乏了還是投降了? 不是不允許自己墜落, 我沒有滴水不進的保護膜。 就是害怕變得面...
    悶熱當(dāng)乘涼閱讀 4,486評論 0 13
  • 感覺自己有點神經(jīng)衰弱,總是覺得手機響了;屋外有人走過;每次媽媽不聲不響的進房間突然跟我說話,我都會被嚇得半死!一整...
    章魚的擁抱閱讀 2,400評論 4 5

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