RxSwift功能分享

1,272 阅读9分钟

关于 当前版本

RxSwift:5.0、RxCocoa: 5.0

链接:中文链接

RxSwift是什么?

RxSwift是一个用于Swift语言,构建函数响应式编程范式应用的框架。 该框架自定义了可异步产生事件的序列,基于订阅-发布模式对事件进行响应,帮助开发人员进行声明式编程。

使用RxSwift的好处?

结合Swift语言,利用RxSwift构建的应用有如下好处?

  1. 易复用: 框架提供的众多操作符方便用于函数的变换。 事件输入、结果输出的函数,方便在多个地方使用。

  2. 清晰: 声明式的编程使得事件和响应处于同一个代码块。 相反例子:系统提供的Target-Action模式,事件绑定代码和事件响应代码处于不同的代码块

声明是不可变的。

  1. 易扩展: 通过对序列的变换方便扩展出不同的功能。

  2. 统一代码风格 : 在该框架中,一切都可以被抽象成可被监听的序列。

下面通过下面的demo了解该框架的使用

City Searcher

在该demo中有一个UISearchBar和一个UITableView。响应用户输入的城市检索,在列表中显示符合条件的城市名称。

详情见:CitySearcherViewController.

版本1

let observable = kSearchBar.rx.text
observable.orEmpty // 非可选
                .subscribe(onNext: {[weak self] (query) in
                    guard let strongSelf = self else {
                        return
                    }
                    strongSelf.kShowCities = strongSelf.allCities().filter({ $0.hasPrefix(query) })
                    strongSelf.kTableView.reloadData()
            }).disposed(by: rx.disposeBag)

对于上面的代码,解释如下:

  • kSearchBar.rx.text:生成一个可监听序列,元素为输入框中的字符串
  • orEmpty:操作符。将String?转换为String类型的函数。这样订阅者获取到的元素将是String类型
  • subscribe(onNext:):订阅或者响应输入的改变。
  • disposed(by: rx.disposeBag):用rx.disposeBag对象管理以上订阅过程中产生的可清除资源。

版本2

let observable = kSearchBar.rx.text
            observable.orEmpty // 非可选
                .debounce(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance)
                .distinctUntilChanged()
                .subscribe(onNext: {[weak self] (query) in
                    guard let strongSelf = self else {
                        return
                    }
                    strongSelf.kShowCities = strongSelf.allCities().filter({ $0.hasPrefix(query) })
                    strongSelf.kTableView.reloadData()
            }).disposed(by: rx.disposeBag)

该版本2较版本1,新增元素产生的频率及条件。

  • debounce(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance):控制事件发出的频率。这里是0.5s产生事件。(操作符)
  • distinctUntilChanged:事件发出的条件。只有元素发生变化的时候才发出。(操作符)

版本3

let observable = kSearchBar.rx.text
            observable.orEmpty // 非可选
                .debounce(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance)
                .distinctUntilChanged()
                .filter({ !$0.isEmpty })
                .subscribe(onNext: {[weak self] (query) in
                    guard let strongSelf = self else {
                        return
                    }
                    strongSelf.kShowCities = strongSelf.allCities().filter({ $0.hasPrefix(query) })
                    strongSelf.kTableView.reloadData()
            }).disposed(by: rx.disposeBag)

该版本3较版本2,新增过滤掉输入为空的情况。

  • filter({ !$0.isEmpty }):过滤输入为空字符串的元素。也就是当输入框中为空时,不会触发数据处理。

Observer

一切可以对序列进行监听并进行响应都叫观察者。Swift中具体表现为函数、或者封装后的AnyObserver、Binder。

AnyObserver

任意观察者

let anyObserver = AnyObserver<Void>.init {[weak self] (_) in
            debugPrint(“前一个订阅者响应”)
        }

Binder

特征观察者,常用来UI层的观察者。

  • 不会处理错误事件
  • 在给定线程订阅,默认为主线程
extension Reactive where Base: UIActivityIndicatorView {

    /// Bindable sink for `startAnimating()`, `stopAnimating()` methods.
    public var isAnimating: Binder<Bool> {
        return Binder(self.base) { activityIndicator, active in
            if active {
                activityIndicator.startAnimating()
            } else {
                activityIndicator.stopAnimating()
            }
        }
    }

}

Observable创建

可监听序列的创建方式。

为方便叙述,以下用序列代替可监听序列,只在存在Swift系统内置序列时加一区分。

  1. creat

通过指定描述事件产生过程的闭包函数实现

extension Reactive where Base: UIActivityIndicatorView {
    public var isAnimating: Binder<Bool> {
        return Binder(self.base) { activityIndicator, active in
            if active {
                activityIndicator.startAnimating()
            } else {
                activityIndicator.stopAnimating()
            }
        }
    }
}
  1. asObservable

通过把可监听类型(通常为特征序列)转化为序列

let subject1 = BehaviorSubject(value: “🍎”).asObservable()
  1. deferred

包装可监听序列的懒序列构建方式,只有当被订阅的时候才创建序列

// 现执行下面的订阅方法,然后执行闭包中的输出方法
let observable = Observable.deferred { () -> Observable<Int> in
            debugPrint(“create”)
            return Observable.create { (observer) -> Disposable in
                observer.onNext(1)
                observer.onNext(2)
                observer.onCompleted()
                return Disposables.create()
            }
        }
observable.subscribe(onNext: { (value) in
            debugPrint(value)
        }, onError: { (error) in
            debugPrint(error)
        }, onCompleted: {
            debugPrint("onCompleted")
        }) {
            debugPrint("onDisposed")
        }.disposed(by: rx.disposeBag)
  1. empty

创建一个空序列,只发出完成事件

let emptyObservable = Observable<Int>.empty()
  1. error

创建一个发出且仅发出一次错误事件的序列

let observable = Observable<Int>.error(CustomError.error)
  1. interval

创建周期性发出元素的序列

let observable = Observable<Int>.interval(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
  1. never

创建不会发出任何事件的序列

let observable = Observable<Int>.never()
  1. just

创建只产生一个元素的序列。产生元素之后就会产生完成事件

let observable = Observable<Int>.just(1)
  1. of

通过Swift内置序列创建可监听序列

let observable = Observable<Int>.of(1, 2, 3, 4)
  1. range

通过指定一个整形范围创建序列

let observable = Observable.range(start: 0, count: 12)
  1. repeatElement

创建重复产生指定元素的序列

let observable = Observable<Int>.repeatElement(2)
  1. timer

创建延迟指定时间产生元素的序列

let timerObservable = Observable<Int>.timer(RxTimeInterval.seconds(2), scheduler: MainScheduler.instance)
  1. from

根据指定Swift内置序列创建序列

let observable = Observable<Int>.from([1, 2, 3, 4])

特征序列

根据序列产生事件的不同、是否共享附加作用以及被订阅时所在队列的不同,序列分为不同的特征序列。

  1. Single

该序列有如下特征:

  • 要么只能发出一个元素
  • 要么产生一个error事件
  • 不会共享附加作用

注:共享附加作用是指序列被多次订阅时,只会产生一个源Observable。

func getRepo(_ repo: String = “RxSwift”) -> Single<[String: Any]> {
            return Single<[String: Any]>.create { (single) -> Disposable in
                let url = URL(string: “https://api.github.com/repos/\(repo)”)!
                let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
                    if let error = error {
                        /// 产生一个错误
                        single(.error(error))
                    }

                    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()
                }
            }
        }

let observable = getRepo()
        observable.subscribe(onSuccess: { (value) in
            debugPrint(value)
        }) { (error) in
            debugPrint("onCompleted")
        }.disposed(by: rx.disposeBag)
  1. Completable
  • 发出零个元素
  • 产生一个completed事件或者产生一个error事件
  • 不会共享附加作用
let observable = Completable.create { (observer) -> Disposable in
            observer(.completed)
            return Disposables.create()
        }
[image:C5CBCC7A-86E3-4E81-8193-37EA98FF35BC-7562-0000275EFFFD5D2D/1578897839206_60pt @2x.png]
 observable.subscribe(onCompleted: {
            debugPrint(“onCompleted”)
        }) { (error) in
            debugPrint(“\(error)”)
        }.disposed(by: rx.disposeBag)
  1. Maybe
  • 要么产生一个元素、要么产生一个completed事件、要么产生一个error事件
  • 不会共享附加作用
let observable = Maybe<Int>.create { (observer) -> Disposable in
//            observer(.completed)
//            observer(.error(DataError.cantParseJson))
            observer(.success(1))
            return Disposables.create()
        }
observable.subscribe(onSuccess: { (value) in
            debugPrint(value)
        }, onError: { (error) in
            debugPrint(error)
        }) {
            debugPrint(“onCompleted”)
        }.disposed(by: rx.disposeBag)
  1. Driver
  • 不会产生error事件
  • 一定在MainScheduler监听(主线程监听)
  • 共享附加作用

如下demo,用户输入的库名改变的时候自动发起网络请求,并将请求结果绑定到列表中。

转变模式为:输入序列 -> 网络请求 -> 库模型序列

因为UI刷新需要在主线程,并且这里不处理错误的情况(后续有错误处理的方法),满足Driver序列的特性,所以库模型序列构造为Driver类型。

// 构建输入序列
        let searchObservable = kSearchBar.rx.text.orEmpty
            .filter { !$0.isEmpty }
            .debounce(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance)
            .distinctUntilChanged()

        // 输入转化为网络请求后的库模型序列
        let vm = RepositoryViewModel.init(repositoryName: searchObservable)

        // 绑定到列表
        vm.repositories.drive(kTableView.rx.items(cellIdentifier: kCellReuseId, cellType: UITableViewCell.self)) { (row, element, cell) in
            cell.textLabel?.text = element.name
            cell.selectionStyle = .none
            cell.accessoryType = .disclosureIndicator
        }.disposed(by: rx.disposeBag)
/// 发起网络请求
    ///
    /// 返回值:库模型序列
    private func requestRepositories() -> Driver<[Repository]> {
        // 解释
        // subscribeOn:调度输入源序列的构建是在住线程
        // observeOn:调度序列的监听是在子线程,这样一来网络任务的执行是在子线程,防止阻塞UI
        // RxAlamofire:请求结束的回调是在住线程
        // observeOn:调度到子线程,目的是使json -> model 的任务在子线程执行
        // observeOn: 调度到主线程,满足Driver的特性
        return repositoryName
        .subscribeOn(MainScheduler.instance)
        .observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
        .flatMapLatest { text -> Observable<(HTTPURLResponse, Any)> in
            debugPrint("flatMapLatest: \(Thread.current)")
            let observable = RxAlamofire
                .requestJSON(.get, "https://api.github.com/users/\(text)/repos")
                .debug().catchError { error in return Observable.never() }
            return observable
        }
        .observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
        .map { (response, json) -> [Repository] in
            debugPrint(“map: \(Thread.current)”)
            if let repos = Mapper<Repository>().mapArray(JSONObject: json) {
                return repos
            } else {
                return []
            }
        }
        .observeOn(MainScheduler.instance)
        .asDriver(onErrorJustReturn: [])
    }
  1. Signal
  • 不会产生error事件
  • 一定在MainScheduler监听(主线程监听)
  • 共享附加作用
  • 不会对新观察者回放最新的元素

下面的demo是在按钮被点击前后分别有一个订阅者(输出),如果为Driver序列,则按钮被点击后会输出“后一个订阅者响应”。相反如果为Signal,则不会输出“后一个订阅者响应”。

private func setupHandings() {
        let anyObserver = AnyObserver<Void>.init {[weak self] (_) in
            debugPrint(“前一个订阅者响应”)
        }
        // ControlEvent序列转化为Signal序列
        func test1() {
            kSignal = kTapButton.rx.tap.asSignal()
            kSignal?.emit(to: anyObserver).disposed(by: rx.disposeBag)
        }

        func test2() {
            kDriver = kTapButton.rx.tap.asDriver()
            kDriver?.drive(anyObserver).disposed(by: rx.disposeBag)
        }
        if kTest1 {
            test1()
        }else {
            test2()
        }
    }
@IBAction func tapAction(_ sender: Any) {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) { [weak self] in
            guard let strongSelf = self else {
                return
            }

            let observer: () -> Void = {
                debugPrint(“后一个订阅者响应”)
            }

            if strongSelf.kTest1 {
                // 由于Signal不会对观察者回上最新的元素,所以不会立刻输出“后一个订阅者响应”
                strongSelf.kSignal?.emit(onNext: { (_) in
                    observer()
                }).disposed(by: strongSelf.rx.disposeBag)
            }else {
                // 由于Driver会对观察者回上最新的元素,所以会立刻输出“后一个订阅者响应”
                strongSelf.kDriver?.drive(onNext: { (_) in
                    observer()
                }).disposed(by: strongSelf.rx.disposeBag)
            }
        }
    }
  1. ControlEvent
  • 不会产生error事件
  • 一定在MainScheduler订阅(主线程订阅)
  • 一定在MainScheduler监听(主线程监听)
  • 共享附加作用
kButton.rx.tap.subscribe(onNext: { (_) in
            debugPrint(“被点击了”)
        }).disposed(by: rx.disposeBag)

Observable&&Observer

以上讲到了序列和观察者,RxSwift中存在一些既可以作为观察者又可以作为序列的类。

这些类之间比较大的一个区别是新被订阅时如何向订阅者发送之前的元素

  1. AsyncSubject

有如下特征:

  • 在源Observable产生完成事件之后紧接着发出一个最新的元素
  • 如果源Observable没有发出过任何元素,则只发出一个完成事件
  • 如果源Observable因产生了一个error事件而终止,则只发出error事件
private let subject = AsyncSubject<Int>()

    override func viewDidLoad() {
        super.viewDidLoad()
        test1()
    }
    
    private func test1() {
        subject.subscribe(onNext: { (value) in
            print(“value: \(value)”)
        }, onError: { (error) in
            print(“error: \(error)”)
        }, onCompleted: {
            print(“完成”)
        }).disposed(by: rx.disposeBag)
        
        subject.onNext(1)
        subject.onNext(2)
        subject.onNext(3)
        subject.onCompleted()
        // 输出  value: 3 \n 完成
    }
  1. PublishSubject

有如下特征:

  • 其将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者
  • 如果因为产生错误事件而导致中止,则向观察者发送该错误事件
  • 如果产生了完成事件,则向观察者发送完成事件
let subject = PublishSubject<Int>()

        subject.subscribe(onNext: { (value) in
            print(“subscribe1 : value: \(value)”)
        }, onError: { (error) in
            print(“subscribe1 : error: \(error)”)
        }, onCompleted: {
            print(“subscribe1 : 完成”)
        }).disposed(by: rx.disposeBag)

        subject.onNext(1)
        subject.onNext(2)

        subject.subscribe(onNext: { (value) in
            print(“subscribe2 : value: \(value)”)
        }, onError: { (error) in
            print(“subscribe2 : error: \(error)”)
        }, onCompleted: {
            print("subscribe2 : 完成")
        }).disposed(by: rx.disposeBag)

        subject.onNext(11)
        subject.onNext(22)

        subject.onCompleted()
  1. ReplaySubject

有如下特征:

  • 将对观察者发送全部的元素(符合限制条件,个数限制或者时间限制),无论观察者是何时进行订阅的
  • 如果源Observable产生一个完成事件,则向所有的观察者发送完成事件
  • 如果源Observable产生一个错误事件,则向所有的观察者发送完成错误
// 创建一个对回放元素不加以限制的序列
let subject = ReplaySubject<Int>.createUnbounded()
subject.subscribe(onNext: { (value) in
            print(“subscribe1 : value: \(value)”)
        }, onError: { (errro) in
            print(“subscribe1 : error: \(errro)”)
        }, onCompleted: {
            print(“subscribe1 : 完成”)
        }).disposed(by: rx.disposeBag)

        subject.onNext(0)
        subject.onNext(1)

        subject.subscribe(onNext: { (value) in
            print(“subscribe2 : value: \(value)”)
        }, onError: { (errro) in
            print("subscribe2 : error: \(errro)")
        }, onCompleted: {
            print("subscribe2 : 完成")
        }).disposed(by: rx.disposeBag)

        subject.onNext(2)
        subject.onNext(3)

        subject.onCompleted()
  1. BehaviorSubject

有如下特征:

  • 可提供默认元素
  • 当观察者对BehaviorSubject进行订阅时,会将源Observable最新的元素发送出来,如果没有最新的元素则发送默认元素
  • 如果源Observable产生一个完成事件,则向所有的观察者发送完成事件
  • 如果源Observable产生一个错误事件,则向所有的观察者发送完成错误
let subject = BehaviorSubject<Int>(value: -1)
        subject.subscribe(onNext: { (value) in
            print(“subscribe1 : value: \(value)”)
        }, onError: { (errro) in
            print(“subscribe1 : error: \(errro)”)
        }, onCompleted: {
            print(“subscribe1 : 完成”)
        }).disposed(by: rx.disposeBag)

        subject.onNext(0)
        subject.onNext(1)

        subject.subscribe(onNext: { (value) in
            print(“subscribe2 : value: \(value)")
        }, onError: { (errro) in
            print(“subscribe2 : error: \(errro)”)
        }, onCompleted: {
            print("subscribe2 : 完成")
        }).disposed(by: rx.disposeBag)

        subject.onNext(2)
        subject.onNext(3)

        subject.onCompleted()
  1. ControlProperty

有如下特征:

  • 不会产生error事件
  • 一定在 MainScheduler 订阅(主线程订阅)
  • 一定在 MainScheduler 监听(主线程监听)
  • 共享附加作用

输入框作为序列,文本Label作为观察者,同步用户输入显示在文本Label上

 // 作为序列
let observable = kInputTextField.rx.text.orEmpty.asDriver()
// 作为观察者
let observer = kResultLabel.rx.text
observable.drive(observer).disposed(by: rx.disposeBag)

Operator

操作符是RxSwift中创建特定功能的新序列或者变换旧序列生成新序列的函数.。

这里挑选几个常用的用来变换序列的操作符。

  1. filter

过滤出满足条件的元素,生成新的序列

// 过滤出大于2的元素
let subject = Observable.from([1, 2, 3, 4, 5]).filter { $0 > 2 }
subject.subscribe(onNext: { (value) in
   debugPrint(value)
}).disposed(by: rx.disposeBag)
  1. map

对序列中的每一个元素应用同一个变换函数生成新的序列。

类似Swift内置中的map函数。

// 元素 * 2
let subject = Observable.from([1, 2, 3, 4, 5]).map { $0 * 2 }
subject.subscribe(onNext: { (value) in
            debugPrint(value)
        }).disposed(by: rx.disposeBag)
  1. zip

组合多个序列,按照每一个序列发出事件的顺序产生新的序列

let subject1 = PublishSubject<Int>()
        let subject2 = PublishSubject<Int>()

        let observable = Observable.zip([subject1, subject2])
        observable.subscribe(onNext: { (values) in
            debugPrint(“\(values[0]) — \(values[1])”)
        }).disposed(by: rx.disposeBag)

        subject1.onNext(1)
        subject1.onNext(2)
        subject2.onNext(3)
        subject2.onNext(4)
  1. combineLatest

组合多个序列。当其中的任何序列产生元素时都会和其它序列中的最新元素组。

合新的元素发出(前提是其它序列也都发出过元素)。

let subject1 = PublishSubject<Int>()
        let subject2 = PublishSubject<Int>()

        let observable = Observable.combineLatest([subject1, subject2])
        observable.subscribe(onNext: { (values) in
            debugPrint(“\(values[0]) — \(values[1])”)
        }).disposed(by: rx.disposeBag)

        subject1.onNext(1)
        subject1.onNext(2)
        subject2.onNext(3)
        subject2.onNext(4)
  1. flatMap

转换元素为新的序列,然后合并这些新的序列为一个序列返回。

let subject1 = PublishSubject<Int>()
        func network(value: Int) -> Observable<Int> {
            return Observable.create { (observer) -> Disposable in
                observer.onNext(value)
                return Disposables.create()
            }
        }

        let observable = subject1.flatMap { network(value: $0) }
        observable.subscribe(onNext: { (values) in
            debugPrint(values)
        }).disposed(by: rx.disposeBag)

        subject1.onNext(1)
        subject1.onNext(2)
        subject1.onNext(3)
        subject1.onNext(4)
  1. switchLatest

将元素为序列的序列转换为新的序列。

只发出序列中最新的‘元素’(序列)发出的元素。

每次接收新的‘元素’(内部序列)时,会订阅该内部序列,并且取消订阅之前的内部序列。

let subject1 = BehaviorSubject(value: “1”)
        let subject2 = BehaviorSubject(value: “2”)
        let subject = BehaviorSubject(value: subject1)

        subject.switchLatest().subscribe(onNext: { (value) in
            debugPrint(value)
        }).disposed(by: rx.disposeBag)

        subject1.onNext(“1.1”)

        subject.onNext(subject2)

        subject2.onNext(“2.1”)
        subject1.onNext(“1.2”)
  1. flatMapLatest

转换元素为新的序列,然后合并这些新的序列为一个序列。

只发出序列中最新的‘元素’(序列)发出的元素。

相当于map + switchLatest

  1. take

只发出序列中的前几个元素

let observable = Observable.of(1, 2, 3)
        observable.take(2).subscribe(onNext: { (value) in
            debugPrint(value)
        }).disposed(by: rx.disposeBag)

可被清除资源

序列、观察者之间的绑定关系,以及序列缓存的元素资源都可以通过可被清除的资源 (Dispoabe)主动调用dispose方法清除。

下面的例子有一个开关,当开关打开的时候会监听到文本输入框输入并输出,当开关关闭的时候就不能监听到。

kSwitch.rx.controlEvent(.valueChanged).asDriver().drive(onNext: {[weak self] (_) in
            guard let on = self?.kSwitch.isOn else {
                return
            }
            if on {
                self?.disposable = self?.textfield.rx.text.orEmpty.subscribe(onNext: { (value) in
                    print(“\(value)”)
                }, onError: { (error) in
                    print(“\(error)”)
                }, onCompleted: {
                    print(“completed”)
                }, onDisposed: {
                    print("disposed")
                })
            }else {
                self?.disposable?.dispose()
            }
        }).disposed(by: rx.disposeBag)

Schedulers

Schedulers是Rx实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行

  1. subscribeOn

用来决定数据序列的构建函数在哪个Scheduler上运行

  1. observeOn

如下面的例子,调度到子线程进行网络请求,调度到主线程监听(实际项目中就会是UI的刷新)。

class SchedulersViewController: BaseViewController {

    // MARK: - Proper methods

    // 开始请求按钮
    private let kBegin: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle(“begin”, for: .normal)
        return button
    }()

    // 待查询城市名称
    private let kCityName = “Chicago”

    // MARK: - Life cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        uiConfig()
        setupHandlings()
    }

    // MARK: - Privte method

    private func uiConfig() {
        view.addSubview(kBegin)
        kBegin.snp.makeConstraints { (make) in
            make.center.equalToSuperview()
        }
    }

    private func setupHandlings() {
        kBegin.rx.tap.subscribe(onNext: {[weak self] (_) in
            guard let strongSelf = self else {
                return
            }
            strongSelf.requestWeatherWith(city: strongSelf.kCityName)
        }).disposed(by: rx.disposeBag)

    }

    // 根据城市名称获取天气状况
    private func requestWeatherWith(city: String) {
        queryLocationIdWith(city: self.kCityName)
            .asObservable()
            .map { $0.arrayValue[0]["woeid"].intValue
            }.flatMapLatest(queryWeathcBy)
            .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { (value) in
                    debugPrint(value)
                    debugPrint("序列监听线程: \(Thread.current)")
            }, onError: { (error) in
                debugPrint(error)
                debugPrint("序列监听线程: \(Thread.current)")
            }).disposed(by: rx.disposeBag)

    }

    // 根据城市名称获取城市id
    private func queryLocationIdWith(city: String) -> Single<JSON> {
        let url = Api.queryCityId + “/?query=\(city)”
        return requestWith(url: url)
    }

    // 根据城市id获取该城市的天气情况
    private func queryWeathcBy(locationid: Int) -> Single<JSON> {
        let url = Api.queryWeatch + “/\(locationid)”
        return requestWith(url: url)
    }

    // 网络请求
    private func requestWith(url: String) -> Single<JSON> {
        return Single.create { (single) -> Disposable in
            let url = URL(string: url)!
            let task = URLSession.shared.dataTask(with: url) { (data, response, error) in

                debugPrint("序列构建线程: \(Thread.current)")

                if let error = error {
                    /// 产生一个错误
                    single(.error(error))
                }

                guard let data = data,
                    let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves) else {
                        /// 产生一个错误
                        single(.error(DataError.cantParseJson))
                    return
                }

                /// 发出一个元素
                single(.success(JSON.init(json)))
            }

            task.resume()
            return Disposables.create {
                task.cancel()
            }
        }
    }

}

错误处理

RxSwift中有三种错误处理机制。

  • retry 重试。如果重试不成功则发出错误事件。

  • catch 恢复。提供默认值代替错误事件发出。

  • materialize 事件封装成Element,dematerialize进行解封,这样就不会有错误事件。

class ErrorHandlingViewController: BaseViewController {
    
    // MARK: - Proper methods
    
    // 待查询城市名称
    private let kCityName = “Chicago”
    
    // MARK: - Life cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        test1()
    }
    
    // MARK: - Privte method
    
    private func test1() {
        let url = Api.queryCityId + “/?query=\(kCityName)”
        let observable = NetworkManager.share.requestWith(url: url).asObservable()
        
        // retry:可以让序列发生错误后重试
        observable.retry(3).subscribe(onNext: { (json) in
            debugPrint(json)
        }, onError: { (error) in
            debugPrint(error)
        }).disposed(by: rx.disposeBag)
    }
    
    private func test2() {
        let url = Api.queryCityId + “/?query=\(kCityName)”
        let observable = NetworkManager.share.requestWith(url: url).asObservable()
        
        // retryWhen: 该操作符描述observable发生错误后,何时进行重试,并且通过闭包里面返回的Observable来控制重试的时机
        
        // eg: 请求失败后,等待5s重试
        let retryDelay = DispatchTimeInterval.seconds(5)
//        observable.retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
//            return Observable.timer(retryDelay, scheduler: MainScheduler.instance)
//        }.subscribe(onNext: { (value) in
//            debugPrint(value)
//        }, onError: { (error) in
//            debugPrint(error)
//        }).disposed(by: rx.disposeBag)
        
        // eg: 请求失败后,等待5s重试
        // 重试4次后仍然失败,就将错误抛出
        let maxRetryCount = 4
        observable.retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
            return rxError.enumerated().flatMap { (arg0) -> Observable<Int> in
                let (index, error) = arg0
                /// 如果大于重试次数,则抛出错误
                guard index < maxRetryCount else {
                    return Observable.error(error)
                }
                /// 等待5s重试
                return Observable.timer(retryDelay, scheduler: MainScheduler.instance)
            }
        }
        .subscribe(onNext: { (value) in
            debugPrint(value)
        }, onError: { (error) in
            debugPrint(error)
        }).disposed(by: rx.disposeBag)
        
    }
    
    private func test3() {
        // catchError - 恢复 : 可以在错误产生时,用一个备用元素或一组备用元素将错误替换
        let url = Api.queryCityId + “/?query=\(kCityName)”
        let observable = NetworkManager.share.requestWith(url: url).asObservable()
        observable.catchErrorJustReturn(JSON())
            .subscribe(onNext: { (value) in
            debugPrint(value)
        }, onError: { (error) in
            debugPrint(error)
        })
            .disposed(by: rx.disposeBag)
        
    }

}

RxSwift架构

RxSwift可以适配多个应用程序架构

MVVM

在vm层,将UI层的输入序列转换为可直接供UI层使用的数据序列(通常为model序列)。

例子将DriverViewController