學(xué)習(xí) RxSwift & RxCocoa

內(nèi)容概覽:
  • Rx Marble Diagrams(寶石圖)
  • 關(guān)鍵概念
  • Event - 事件
  • Observable - 產(chǎn)生事件
  • Observer - 響應(yīng)事件
  • Operator - 創(chuàng)建變化組合事件
  • Disposable - 管理綁定(訂閱)的生命周期
  • Schedulers - 線程隊(duì)列調(diào)配



為什么要使用Rx(ReactiveX)?

  • 簡(jiǎn)化異步操作
  • 簡(jiǎn)化多線程操作
  • 更簡(jiǎn)潔的代碼
  • 多平臺(tái)適用(C++, Java, C#, JavaScript, Python,Scala,Kotlin,Go)

另外,官方文檔解釋了一個(gè)很重要的點(diǎn):ReactiveX不是函數(shù)響應(yīng)式編程(Functional Reactive Programming)!
請(qǐng)不要再被人忽悠,也不要用這個(gè)概念去忽悠別人~


Rx Marble Diagrams(寶石圖)

Observable發(fā)出事件,然后被Observer接收并被轉(zhuǎn)換為其他形式,轉(zhuǎn)換后的事件又繼續(xù)被發(fā)出。
當(dāng)Observable序列完成時(shí),或者出現(xiàn)錯(cuò)誤時(shí),序列被終結(jié)。

Observable是一個(gè)序列,類(lèi)似于Swift中的序列,但是這個(gè)序列可以異步接收元素。
Observable的subscribe方法,類(lèi)似于Swift序列中的makeIterator方法。
Observer(通常是一系列的閉包)需要傳遞給Observable的subscribe,以接收序列的元素。

Rx抽象了時(shí)間狀態(tài)機(jī),我們可以更方便地去完成業(yè)務(wù)邏輯。
否則,我們就要重復(fù)地去編寫(xiě)一些有關(guān)臨時(shí)狀態(tài)轉(zhuǎn)換的邏輯代碼。


寶石圖可以幫助你理解Rx中的操作符

一個(gè)關(guān)于數(shù)字的序列:
--1--2--3--4--5--6--| // 序列完成,并終結(jié)

另一個(gè)關(guān)于字符的序列
--a--b--a--a--a---d---X // 序列發(fā)生錯(cuò)誤,并終結(jié)

有些序列是無(wú)窮無(wú)盡的,比如按鈕點(diǎn)擊事件序列:
---tap-tap-------tap--->


這里有一條基本的規(guī)則:
  • 序列可以產(chǎn)生0個(gè)或多個(gè)元素。
  • 只要序列完成了或者發(fā)生了錯(cuò)誤,序列就不能再產(chǎn)生元素。


關(guān)鍵概念



Event - 事件

/// 代表一系列事件
public enum Event<Element> {
    /// 序列產(chǎn)生了一個(gè)新的元素
    case next(Element)
    /// 創(chuàng)建序列時(shí)產(chǎn)生了一個(gè)錯(cuò)誤,導(dǎo)致序列終止
    case error(Swift.Error)
    /// 序列的所有元素都已經(jīng)成功產(chǎn)生,整個(gè)序列已經(jīng)完成
    case completed
}

請(qǐng)注意,序列產(chǎn)生了錯(cuò)誤,就會(huì)導(dǎo)致序列終止!
有時(shí)候,這并不是你期待的結(jié)果?。?!



Observable - 產(chǎn)生事件

創(chuàng)建Observable,并讓Observer訂閱事件,在事件結(jié)束后釋放觀察者。

typealias JSON = Any

let disposeBag = DisposeBag()

let json: Observable<JSON> = Observable.create { (observer) -> Disposable in
    let task = URLSession.shared.dataTask(with: ...) { data, _, error in
        guard error == nil else {
            observer.onError(error!)
            return
        }
        guard let data = data,
            let jsonObject = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
            else {
            observer.onError(DataError.cantParseJSON)
            return
        }
        observer.onNext(jsonObject)
        observer.onCompleted()
    }
    task.resume()
    return Disposables.create { task.cancel() }
}

json.subscribe(onNext: { json in
    print("取得 json 成功: \(json)")
}, onError: { error in
    print("取得 json 失敗 Error: \(error.localizedDescription)")
}, onCompleted: {
    print("取得 json 任務(wù)成功完成")
}).disposed(by: disposeBag) // 釋放Observers


Observable 的冷與熱

一創(chuàng)建就可以開(kāi)始發(fā)出事件的,就是熱的。
直到有observer訂閱才開(kāi)始發(fā)出事件的,就是冷的!


Observable 特征序列(定制版的Observable)


  • Single
    要么發(fā)出一個(gè)元素,要么產(chǎn)生一個(gè) error 事件。
    一個(gè)比較常見(jiàn)的例子就是執(zhí)行 HTTP 請(qǐng)求,然后返回一個(gè)應(yīng)答或錯(cuò)誤。
    不過(guò)你也可以用 Single 來(lái)描述任何只有一個(gè)元素的序列。

示例Demo:

let disposeBag = DisposeBag()

func getRepo(_ repo: String) -> Single<[String: Any]> {
    return Single<[String: Any]>.create { single in
        let url = URL(string: "https://api.github.com/repos/\(repo)")!
        let task = URLSession.shared.dataTask(with: url) { data, _, error in
            if let error = error {
                single(.error(error))
                return
            }
            guard let data = data,
                  let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves),
                  let result = json as? [String: Any] else {
                single(.error(DataError.cantParseJSON))
                return
            }
            single(.success(result))
        }
        task.resume()
        return Disposables.create { task.cancel() }
    }
}

getRepo("ReactiveX/RxSwift").subscribe(onSuccess: { json in
    print("JSON: ", json)
}, onError: { error in
    print("Error: ", error)
}).disposed(by: disposeBag)

訂閱提供一個(gè) SingleEvent 的枚舉:

public enum SingleEvent<Element> {
    case success(Element)
    case error(Swift.Error)
}


  • Completable
    要么產(chǎn)生一個(gè) completed 事件,要么產(chǎn)生一個(gè) error 事件。
    Completable 適用于那種你只關(guān)心任務(wù)是否完成,而不需要在意任務(wù)返回值的情況。

示例Demo:

let disposeBag = DisposeBag()

func cacheLocally() -> Completable {
    return Completable.create { completable in
       // Store some data locally
       ...
       ...

       guard success else {
           completable(.error(CacheError.failedCaching))
           return Disposables.create {}
       }
       completable(.completed)
       return Disposables.create {}
    }
}

cacheLocally().subscribe(onCompleted: {
    print("Completed with no error")
}, onError: { error in
    print("Completed with an error: \(error.localizedDescription)")
}).disposed(by: disposeBag)

訂閱提供一個(gè) CompletableEvent 的枚舉:

public enum CompletableEvent {
    case error(Swift.Error)
    case completed
}


  • Maybe
    它介于 Single 和 Completable 之間,它要么發(fā)出一個(gè)元素,要么產(chǎn)生一個(gè) completed 事件,要么產(chǎn)生一個(gè) error 事件。
    如果你遇到那種可能需要發(fā)出一個(gè)元素,又可能不需要發(fā)出時(shí),就可以使用 Maybe。

示例Demo:

let disposeBag = DisposeBag()

func generateString() -> Maybe<String> {
    return Maybe<String>.create { maybe in

        maybe(.success("RxSwift"))
        // OR
        maybe(.completed)
        // OR
        maybe(.error(error))
        return Disposables.create {}
    }
}

generateString().subscribe(onSuccess: { element in
    print("Completed with element \(element)")
}, onError: { error in
    print("Completed with an error \(error.localizedDescription)")
}, onCompleted: {
    print("Completed with no element")
}).disposed(by: disposeBag)

訂閱提供一個(gè) MaybeEvent 的枚舉:

public enum MaybeEvent<Element> {
    case success(Element)
    case error(Swift.Error)
    case completed
}


  • Driver
    為UI元素精心準(zhǔn)備的特征序列
    1. 不會(huì)產(chǎn)生 error 事件
    2. 一定在 MainScheduler 監(jiān)聽(tīng)(主線程監(jiān)聽(tīng))
    3. 共享狀態(tài)變化

為什么要使用Driver?


  • ControlEvent
    用于描述 UI 控件所產(chǎn)生的事件(如:按鈕點(diǎn)擊事件、輸入框文本更新事件等)。
    1. 不會(huì)產(chǎn)生 error 事件
    2. 一定在 MainScheduler 訂閱(主線程訂閱)
    3. 一定在 MainScheduler 監(jiān)聽(tīng)(主線程監(jiān)聽(tīng))
    4. 共享狀態(tài)變化



Observer - 響應(yīng)事件

button.rx.tap.subscribe(onNext: { [weak self] in
    self?.showAlert()
}, onError: { error in
    print("發(fā)生錯(cuò)誤: \(error.localizedDescription)")
}, onCompleted: {
    print("任務(wù)完成")
})

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


特征觀察者(定制的Observer)


  • AnyObserver
    可以用來(lái)描敘任意一種觀察者。
URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(onNext: { data in
    print("Data Task Success with count: \(data.count)")
}, onError: { error in
    print("Data Task Error: \(error)")
})
.disposed(by: disposeBag)

以上代碼可以看作:

let observer: AnyObserver<Data> = AnyObserver { (event) in
    switch event {
    case .next(let data):
        print("Data Task Success with count: \(data.count)")
    case .error(let error):
        print("Data Task Error: \(error)")
    default:
        break
    }
}

URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(observer)
.disposed(by: disposeBag)


  • Binder
    Binder有以下特征:
    1. 不會(huì)處理錯(cuò)誤事件
    2. 確保綁定都是在給定 Scheduler 上執(zhí)行(默認(rèn) MainScheduler
let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in
    switch event {
    case .next(let isHidden):
        self?.usernameValidOutlet.isHidden = isHidden
    default:
        break
    }
}

usernameValid
.bind(to: observer)
.disposed(by: disposeBag)

以上代碼如果用Binder實(shí)現(xiàn),效果更佳。

let observer: Binder<Bool> = Binder(usernameValidOutlet) { (view, isHidden) in
    view.isHidden = isHidden
}

usernameValid
.bind(to: observer)
.disposed(by: disposeBag)

Binder 可以只處理 next 事件,并且保證響應(yīng) next 事件的代碼一定會(huì)在給定 Scheduler 上執(zhí)行,這里采用默認(rèn)的 MainScheduler。



RxCocoa中已經(jīng)采用Binder實(shí)現(xiàn)了很多常用的觀察者,比如:

extension Reactive where Base: UIView {
  public var isHidden: Binder<Bool> {
      // self.base是實(shí)際的UI控件對(duì)象
      return Binder(self.base) { view, hidden in
          view.isHidden = hidden
      }
  }
}

extension Reactive where Base: UIControl {
  public var isEnabled: Binder<Bool> {
      return Binder(self.base) { control, value in
          control.isEnabled = value
      }
  }
}

extension Reactive where Base: UILabel {
  public var text: Binder<String?> {
      return Binder(self.base) { label, text in
          label.text = text
      }
  }
}

你也可以用這種方式來(lái)創(chuàng)建自定義的 UI 觀察者


Observable & Observer

有些事物比較特別。它們既是可被監(jiān)聽(tīng)的序列也是觀察者。
有許多 UI 控件都存在這種特性,例如:switch的開(kāi)關(guān)狀態(tài),segmentedControl的選中索引號(hào),datePicker的選中日期等等。

// 作為可被監(jiān)聽(tīng)的序列
let observable = textField.rx.text
observable.subscribe(onNext: { text in show(text: text) })

// 作為觀察者
let observer = textField.rx.text
let text: Observable<String?> = ...
text.bind(to: observer)



框架里面定義了一些輔助類(lèi)型可以幫助你更準(zhǔn)確的描述事物的特征,它們既是可被監(jiān)聽(tīng)的序列也是觀察者。

  • AsyncSubject
    將在源 Observable 產(chǎn)生完成事件后,發(fā)出最后一個(gè)元素(僅僅只有最后一個(gè)元素)。

  • PublishSubject
    發(fā)送訂閱后產(chǎn)生的元素,而在訂閱前發(fā)出的元素將不會(huì)發(fā)送給觀察者。

  • ReplaySubject
    發(fā)送全部的元素(元素個(gè)數(shù)由buffer的大小決定),無(wú)論觀察者是何時(shí)進(jìn)行訂閱的。

  • BehaviorSubject
    當(dāng)觀察者對(duì) BehaviorSubject 進(jìn)行訂閱時(shí),它會(huì)將源 Observable 中最新的元素發(fā)送出來(lái)(如果不存在最新的元素,就發(fā)出默認(rèn)元素)。然后將隨后產(chǎn)生的元素發(fā)送出來(lái)。

  • Variable
    在 Swift 中我們經(jīng)常會(huì)用 var 關(guān)鍵字來(lái)聲明變量。
    RxSwift 提供的 Variable 實(shí)際上是 var 的 Rx 版本,你可以將它看作是 RxVar。
    如果我們聲明的變量需要提供 Rx 支持,那就選用 Variable 這個(gè)類(lèi)型。

  • ControlProperty
    ControlProperty 專(zhuān)門(mén)用于描述 UI 控件屬性的,它具有以下特征:

    1. 不會(huì)產(chǎn)生 error 事件
    2. 一定在 MainScheduler 訂閱(主線程訂閱)
    3. 一定在 MainScheduler 監(jiān)聽(tīng)(主線程監(jiān)聽(tīng))
    4. 共享狀態(tài)變化



Operator - 創(chuàng)建變化組合事件

操作符可以幫助大家創(chuàng)建新的序列,或者變化組合原有的序列,從而生成一個(gè)新的序列。

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)換

// JSON
let json: Observable<JSON> = ...

// map 操作符
json.map(Model.init)
.subscribe(onNext: { model in
    print("取得 Model: \(model)")
})
.disposed(by: disposeBag)

zip - 配對(duì)

// 漢堡
let rxHamburg: Observable<Hamburg> = ...
// 薯?xiàng)l
let rxFrenchFries: Observable<FrenchFries> = ...

// zip 操作符
Observable.zip(rxHamburg, rxFrenchFries)
.subscribe(onNext: { (hamburg, frenchFries) in
    print("取得漢堡: \(hamburg) 和薯?xiàng)l:\(frenchFries)")
})
.disposed(by: disposeBag)

Rx提供了充分的操作符來(lái)幫我們創(chuàng)建序列。當(dāng)然如果內(nèi)置操作符無(wú)法滿足你的需求時(shí),你還可以創(chuàng)建自定義的操作符。

如果你不確定該如何選擇操作符,可以參考 決策樹(shù)。它會(huì)引導(dǎo)你找出合適的操作符。



Disposable - 管理綁定(訂閱)的生命周期

通常來(lái)說(shuō),一個(gè)序列如果發(fā)出了 error 或者 completed 事件,那么所有內(nèi)部資源都會(huì)被釋放。
如果你需要提前釋放這些資源或取消訂閱的話,那么你可以對(duì)返回的 可被清除的資源(Disposable) 調(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 用法:

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 - 線程隊(duì)列調(diào)配

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



一個(gè)比較典型的例子就是,在后臺(tái)發(fā)起網(wǎng)絡(luò)請(qǐng)求,然后解析數(shù)據(jù),最后在主線程刷新頁(yè)面。你就可以先用 subscribeOn 切到后臺(tái)去發(fā)送請(qǐng)求并解析數(shù)據(jù),最后用 observeOn 切換到主線程更新頁(yè)面。

GCD實(shí)現(xiàn):

DispatchQueue.global(qos: .userInitiated).async {
    let data = try? Data(contentsOf: url)
    DispatchQueue.main.async {
        self.data = data
    }
} 

RxSwift實(shí)現(xiàn):

let rxData: Observable<Data> = ...

rxData
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] data in
    self?.data = data
})
.disposed(by: disposeBag)
  • MainScheduler
    MainScheduler 代表主線程。
    如果你需要執(zhí)行一些和 UI 相關(guān)的任務(wù),就需要切換到該 Scheduler 運(yùn)行。

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

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

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



Error Handling - 錯(cuò)誤處理

一旦序列里面產(chǎn)出了一個(gè) error 事件,整個(gè)序列將被終止。RxSwift 主要有兩種錯(cuò)誤處理機(jī)制:

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


retry - 重試

請(qǐng)求 JSON 失敗時(shí),立即重試,重試 3 次后仍然失敗就將錯(cuò)誤拋出:

let rxJson: Observable<JSON> = ...

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

請(qǐng)求 JSON 失敗時(shí),等待 5 秒后重試:

let retryDelay: Double = 5  // 重試延時(shí) 5 秒

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

retryWhen 操作符主要描述應(yīng)該在何時(shí)重試,并且通過(guò)閉包里面返回的 Observable 來(lái)控制重試的時(shí)機(jī)。

如果重試超過(guò) 4 次,就將錯(cuò)誤拋出。如果錯(cuò)誤在 4 次以內(nèi)時(shí),就等待 5 秒后重試:

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)

flatMapWithIndex 操作符可以提供錯(cuò)誤的索引數(shù) index。然后用這個(gè)索引數(shù)判斷是否超過(guò)最大重試數(shù),如果超過(guò)了,就將錯(cuò)誤拋出。如果沒(méi)有超過(guò),就等待 5 秒后重試。


catch - 恢復(fù)

catchError 可以在錯(cuò)誤產(chǎn)生時(shí),用一個(gè)備用元素或者一組備用元素將錯(cuò)誤替換掉。

當(dāng)錯(cuò)誤產(chǎn)生時(shí),就返回一個(gè)空數(shù)組,于是就會(huì)顯示一個(gè)空列表頁(yè):

searchBar.rx.text.orEmpty
...
.flatMapLatest { query -> Observable<[Repository]> in
    ...
    return searchGitHub(query)
        .catchErrorJustReturn([])
}
...
.bind(to: ...)
.disposed(by: disposeBag)

你也可以使用 catchError,當(dāng)錯(cuò)誤產(chǎn)生時(shí),將錯(cuò)誤事件替換成一個(gè)備選序列:

// 先從網(wǎng)絡(luò)獲取數(shù)據(jù),如果獲取失敗了,就從本地緩存獲取數(shù)據(jù)

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)


Result

如果我們只是想給用戶錯(cuò)誤提示,那要如何操作呢?

以下提供一個(gè)最為直接的方案,不過(guò)這個(gè)方案存在一些問(wèn)題:

updateUserInfoButton.rx.tap
.withLatestFrom(rxUserInfo)
.flatMapLatest { userInfo -> Observable<Void> in
    return update(userInfo)
}
.observeOn(MainScheduler.instance)
.subscribe(onNext: {
    print("用戶信息更新成功")
}, onError: { error in
    print("用戶信息更新失?。?\(error.localizedDescription)")
})
.disposed(by: disposeBag)

這樣實(shí)現(xiàn)是非常直接的。但是 一旦網(wǎng)絡(luò)請(qǐng)求操作失敗了,序列就會(huì)終止??!整個(gè)訂閱將被取消??!
如果用戶再次點(diǎn)擊更新按鈕,就無(wú)法再次發(fā)起網(wǎng)絡(luò)請(qǐng)求進(jìn)行更新操作了。

為了解決這個(gè)問(wèn)題,我們需要選擇合適的方案來(lái)進(jìn)行錯(cuò)誤處理。例如使用枚舉 Result:

// 自定義一個(gè)枚舉類(lèi)型 Result
public enum Result<T> {
    case success(T)
    case failure(Swift.Error)
}

然后之前的代碼需要修改成:

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)

這樣我們的錯(cuò)誤事件被包裝成了 Result.failure(Error) 元素,就不會(huì)終止整個(gè)序列。就算網(wǎng)絡(luò)請(qǐng)求失敗,整個(gè)訂閱依然存在。如果用戶再次點(diǎn)擊更新按鈕,也是能夠發(fā)起網(wǎng)絡(luò)請(qǐng)求進(jìn)行更新操作的。

除此之外,強(qiáng)烈建議閱讀 How to handle errors in RxSwift



最后,對(duì)于初學(xué)者,建議將RxSwift代碼倉(cāng)庫(kù)下載到本地。

然后,打開(kāi) Rx.xcworkspace
在左上角的 Schema 選中 RxSwift-macOS,然后 Build (快捷鍵:Command + B)項(xiàng)目。
在Build結(jié)束后,進(jìn)入 Project navigator (快捷鍵:Command + 1) 并找到 Rx - Rx.playground,然后打開(kāi)調(diào)試窗口(快捷鍵:Shift + Command + Y) 以查看示例代碼執(zhí)行效果。

在這個(gè)Playground中,官方對(duì) 所有的操作符 進(jìn)行了闡釋?zhuān)@可以幫助你迅速掌握RxSwift。

最后的最后,強(qiáng)烈建議初學(xué)者閱讀 RxSwift - Getting Started?。?!




參考文章:
ReactiveX Introduction
Github: ReactiveX / RxSwift
RxMarbles(常見(jiàn)寶石圖)
RxSwift - Getting Started
RxSwift 中文文檔 (本文大部分內(nèi)容來(lái)源于此文檔)
ReactiveX文檔中文翻譯
How to handle errors in RxSwift



如需轉(zhuǎn)載,請(qǐng)注明出處,謝謝 ~

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

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

  • 最近在學(xué)習(xí)RxSwift相關(guān)的內(nèi)容,在這里記錄一些基本的知識(shí)點(diǎn),以便今后查閱。 Observable 在RxSwi...
    L_Zephyr閱讀 1,895評(píng)論 1 4
  • Introduction: Creating and Subscribing to Observables: Th...
    loongod閱讀 870評(píng)論 0 0
  • 一、RxJava操作符概述 RxJava中的操作符就是為了提供函數(shù)式的特性,函數(shù)式最大的好處就是使得數(shù)據(jù)處理簡(jiǎn)潔易...
    BrotherChen閱讀 1,780評(píng)論 0 10
  • 一、RxJava操作符概述 RxJava中的操作符就是為了提供函數(shù)式的特性,函數(shù)式最大的好處就是使得數(shù)據(jù)處理簡(jiǎn)潔易...
    測(cè)天測(cè)地測(cè)空氣閱讀 683評(píng)論 0 1
  • 一、RxJava操作符概述 RxJava中的操作符就是為了提供函數(shù)式的特性,函數(shù)式最大的好處就是使得數(shù)據(jù)處理簡(jiǎn)潔易...
    無(wú)求_95dd閱讀 3,493評(píng)論 0 21

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