RxSwift学习之十 (基础使用篇 1- 序列,订阅,销毁)

2019-10-18  本文已影响0人  孔雨露

@[TOC](RxSwift学习之十 (基础使用篇 1- 序列,订阅,销毁))

1. RxSwift简介

1)在编写代码时我们经常会需要检测某些值的变化(比如:textFiled 输入值的变化、数据请求完成或失败的变化),然后进行相应的处理。
过去针对不同的情况,我们需要采用不同的事件传递方法去处理,比如:delegate、notification、target-action、KVO 等等。
而 RectiveX 机制(由 RxSwift 实现)的出现,让程序里的事件传递响应方法做到统一。将之前那些常用的事件传递方法(比如:delegate、notification、target-action 等等),全部替换成 Rx 的“信号链”方式。
(2)如果我们平时使用的是 MVVM 开发模式的话,通过 RxSwift 可以获得更加方便的数据绑定的方法,使得 MVVM 开发更加如虎添翼。

RxSwift:它只是基于 Swift 语言的 Rx 标准实现接口库,所以 RxSwift 里不包含任何 Cocoa 或者 UI 方面的类。
RxCocoa:是基于 RxSwift 针对于 iOS 开发的一个库,它通过 Extension 的方法给原生的比如 UI 控件添加了 Rx 的特性,使得我们更容易订阅和响应这些控件的事件。

2. RxSwift简单使用

2.1 响应式编程与传统式编程的比较样例

  1. 有这么一个需求:
    表格中显示的是歌曲信息(歌名,以及歌手)
    点击选中任意一个单元格,在控制台中打印出对应的歌曲信息。


    在这里插入图片描述
  2. 按传统方式:首先我们创建一个 Music 的结构体,用来保存歌曲名称、歌手名字。此外它还遵循 CustomStringConvertible 协议,方便我们输出调试。
import UIKit
 
//歌曲结构体
struct Music {
    let name: String //歌名
    let singer: String //演唱者
     
    init(name: String, singer: String) {
        self.name = name
        self.singer = singer
    }
}
 
//实现 CustomStringConvertible 协议,方便输出调试
extension Music: CustomStringConvertible {
    var description: String {
        return "name:\(name) singer:\(singer)"
    }
}

2.1.1 传统编程

  1. 首先写一个 ViewModel
import Foundation
 
//歌曲列表数据源
struct MusicListViewModel {
    let data = [
        Music(name: "无条件", singer: "陈奕迅"),
        Music(name: "你曾是少年", singer: "S.H.E"),
        Music(name: "从前的我", singer: "陈洁仪"),
        Music(name: "在木星", singer: "朴树"),
    ]
}
  1. 视图控制器代码(ViewController.swift)
import UIKit
import RxSwift
 
class ViewController: UIViewController {
 
    //tableView对象
    @IBOutlet weak var tableView: UITableView!
     
    //歌曲列表数据源
    let musicListViewModel = MusicListViewModel()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //设置代理
        tableView.dataSource = self
        tableView.delegate = self
    }
}
 
extension ViewController: UITableViewDataSource {
    //返回单元格数量
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return musicListViewModel.data.count
    }
     
    //返回对应的单元格
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell")!
        let music = musicListViewModel.data[indexPath.row]
        cell.textLabel?.text = music.name
        cell.detailTextLabel?.text = music.singer
        return cell
    }
}
 
extension ViewController: UITableViewDelegate {
    //单元格点击
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("你选中的歌曲信息【\(musicListViewModel.data[indexPath.row])】")
    }
}

2.1.2 Rxswift编程

  1. ViewModel 做些修改
    • 这里我们将 data 属性变成一个可观察序列对象(Observable Squence),而对象当中的内容和我们之前在数组当中所包含的内容是完全一样的。
    • 关于可观察序列对象在后面的文章中我会详细介绍。简单说就是“序列”可以对这些数值进行“订阅(Subscribe)”,有点类似于“通知(NotificationCenter)”
import RxSwift
 
//歌曲列表数据源
struct MusicListViewModel {
    let data = Observable.just([
        Music(name: "无条件", singer: "陈奕迅"),
        Music(name: "你曾是少年", singer: "S.H.E"),
        Music(name: "从前的我", singer: "陈洁仪"),
        Music(name: "在木星", singer: "朴树"),
    ])
}
  1. 视图控制器代码(ViewController.swift
    • 这里我们不再需要实现数据源和委托协议了。而是写一些响应式代码,让它们将数据和 UITableView 建立绑定关系。
    • 算了下这里我们只需要 31 行代码,同之前的相比,一下减少了 1/4 代码量。而且代码也更清爽了些。
    • 代码的简单说明:
      DisposeBag:作用是 Rx 在视图控制器或者其持有者将要销毁的时候,自动释法掉绑定在它上面的资源。它是通过类似“订阅处置机制”方式实现(类似于 NotificationCenter 的 removeObserver)。
      rx.items(cellIdentifier:):这是 Rx 基于 cellForRowAt 数据源方法的一个封装。传统方式中我们还要有个 numberOfRowsInSection 方法,使用 Rx 后就不再需要了(Rx 已经帮我们完成了相关工作)。
      rx.modelSelected: 这是 Rx 基于 UITableView 委托回调方法 didSelectRowAt 的一个封装。

import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
 
    //tableView对象
    @IBOutlet weak var tableView: UITableView!
     
    //歌曲列表数据源
    let musicListViewModel = MusicListViewModel()
     
    //负责对象销毁
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //将数据源数据绑定到tableView上
        musicListViewModel.data
            .bind(to: tableView.rx.items(cellIdentifier:"musicCell")) { _, music, cell in
                cell.textLabel?.text = music.name
                cell.detailTextLabel?.text = music.singer
            }.disposed(by: disposeBag)
         
        //tableView点击响应
        tableView.rx.modelSelected(Music.self).subscribe(onNext: { music in
            print("你选中的歌曲信息【\(music)】")
        }).disposed(by: disposeBag)
    }
}

2.2 Observable介绍、创建可观察序列

public enum Event<Element> {
    /// Next element is produced.
    case next(Element)
 
    /// Sequence terminated with an error.
    case error(Swift.Error)
 
    /// Sequence completed successfully.
    case completed
}

2.2.1 Observable 与 Sequence比较

2.2.2 创建 Observable 序列

  1. just() 方法

(1)该方法通过传入一个默认值来初始化。
(2)下面样例我们显式地标注出了 observable 的类型为 Observable<Int>,即指定了这个 Observable 所发出的事件携带的数据类型必须是 Int 类型的。

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

(1)该方法可以接受可变数量的参数(必需要是同类型的)
(2)下面样例中我没有显式地声明出 Observable 的泛型类型,Swift 也会自动推断类型。

let observable = Observable.of("A", "B", "C")
  1. from() 方法

(1)该方法需要一个数组参数。
(2)下面样例中数据里的元素就会被当做这个 Observable 所发出 event 携带的数据内容,最终效果同上面饿 of() 样例是一样的。

let observable = Observable.from(["A", "B", "C"])
  1. empty() 方法
    该方法创建一个空内容的 Observable 序列。
let observable = Observable<Int>.never()
  1. never() 方法
    该方法创建一个永远不会发出 Event(也不会终止)的 Observable 序列。
let observable = Observable<Int>.never()
  1. error() 方法
    该方法创建一个不做任何操作,而是直接发送一个错误的 Observable 序列。
enum MyError: Error {
    case A
    case B
}
         
let observable = Observable<Int>.error(MyError.A)
  1. range() 方法

(1)该方法通过指定起始和结束数值,创建一个以这个范围内所有值作为初始值的 Observable 序列。

(2)下面样例中,两种方法创建的 Observable 序列都是一样的。

//使用range()
let observable = Observable.range(start: 1, count: 5)
 
//使用of()
let observable = Observable.of(1, 2, 3 ,4 ,5)
  1. repeatElement() 方法
    该方法创建一个可以无限发出给定元素的 Event 的 Observable 序列(永不终止)。
let observable = Observable.repeatElement(1)
  1. generate() 方法

(1)该方法创建一个只有当提供的所有的判断条件都为 true 的时候,才会给出动作的 Observable 序列。
(2)下面样例中,两种方法创建的 Observable 序列都是一样的。

//使用generate()方法
let observable = Observable.generate(
    initialState: 0,
    condition: { $0 <= 10 },
    iterate: { $0 + 2 }
)
 
//使用of()方法
let observable = Observable.of(0 , 2 ,4 ,6 ,8 ,10)
  1. create() 方法

(1)该方法接受一个 block 形式的参数,任务是对每一个过来的订阅进行处理。
(2)下面是一个简单的样例。为方便演示,这里增加了订阅相关代码

//这个block有一个回调参数observer就是订阅这个Observable对象的订阅者
//当一个订阅者订阅这个Observable对象的时候,就会将订阅者作为参数传入这个block来执行一些内容
let observable = Observable<String>.create{observer in
    //对订阅者发出了.next事件,且携带了一个数据"hangge.com"
    observer.onNext("hangge.com")
    //对订阅者发出了.completed事件
    observer.onCompleted()
    //因为一个订阅行为会有一个Disposable类型的返回值,所以在结尾一定要returen一个Disposable
    return Disposables.create()
}
 
//订阅测试
observable.subscribe {
    print($0)
}
  1. deferred() 方法

(1)该个方法相当于是创建一个 Observable 工厂,通过传入一个 block 来执行延迟 Observable 序列创建的行为,而这个 block 里就是真正的实例化序列对象的地方。
(2)下面是一个简单的演示样例:

//用于标记是奇数、还是偶数
var isOdd = true
 
//使用deferred()方法延迟Observable序列的初始化,通过传入的block来实现Observable序列的初始化并且返回。
let factory : Observable<Int> = Observable.deferred {
     
    //让每次执行这个block时候都会让奇、偶数进行交替
    isOdd = !isOdd
     
    //根据isOdd参数,决定创建并返回的是奇数Observable、还是偶数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)
}
 
//第2次订阅测试
factory.subscribe { event in
    print("\(isOdd)", event)
}

运行结果如下,可以看到我们两次订阅的得到的 Observable 是不一样的:


在这里插入图片描述
  1. interval() 方法

(1)这个方法创建的 Observable 序列每隔一段设定的时间,会发出一个索引数的元素。而且它会一直发送下去。
(2)下面方法让其每 1 秒发送一次,并且是在主线程(MainScheduler)发送。

let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable.subscribe { event in
    print(event)
}
  1. timer() 方法
//5秒种后发出唯一的一个元素0
let observable = Observable<Int>.timer(5, scheduler: MainScheduler.instance)
observable.subscribe { event in
    print(event)
}
//延时5秒种后,每隔1秒钟发出一个元素
let observable = Observable<Int>.timer(5, period: 1, scheduler: MainScheduler.instance)
observable.subscribe { event in
    print(event)
}

2.3 Observable订阅、事件监听、订阅销毁

2.3.1 Observable订阅

2.3.1.1 第一种订阅方式

let observable = Observable.of("A", "B", "C")
         
observable.subscribe { event in
    print(event)
}

运行结果如下,可以看到:

image

初始化 Observable 序列时设置的默认值都按顺序通过 .next 事件发送出来。
当 Observable 序列的初始数据都发送完毕,它还会自动发一个 .completed 事件出来。

let observable = Observable.of("A", "B", "C")
         
observable.subscribe { event in
    print(event.element)
}

运行结果如下:


image

2.3.1.2 第二种订阅方式

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

运行结果如下:


image
let observable = Observable.of("A", "B", "C")
         
observable.subscribe(onNext: { element in
    print(element)
})

运行结果如下:
A
B
C

2.3.2 事件监听

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

2.3.3 订阅销毁

2.3.3.1 Observable 从创建到终结流程

2.3.3.2 dispose() 方法

-(1)使用该方法我们可以手动取消一个订阅行为。
-(2)如果我们觉得这个订阅结束了不再需要了,就可以调用 dispose() 方法把这个订阅给销毁掉,防止内存泄漏。
-(3)当一个订阅行为被 dispose 了,那么之后 observable 如果再发出 event,这个已经 dispose 的订阅就收不到消息了。下面是一个简单的使用样例。

let observable = Observable.of("A", "B", "C")
         
//使用subscription常量存储这个订阅方法
let subscription = observable.subscribe { event in
    print(event)
}
         
//调用这个订阅的dispose()方法
subscription.dispose()

2.3.3.13 DisposeBag

  1. 我们可以把一个 DisposeBag 对象看成一个垃圾袋,把用过的订阅行为都放进去。
  2. 而这个 DisposeBag 就会在自己快要 dealloc 的时候,对它里面的所有订阅行为都调用 dispose() 方法。
let disposeBag = DisposeBag()
         
//第1个Observable,及其订阅
let observable1 = Observable.of("A", "B", "C")
observable1.subscribe { event in
    print(event)
}.disposed(by: disposeBag)
 
//第2个Observable,及其订阅
let observable2 = Observable.of(1, 2, 3)
observable2.subscribe { event in
    print(event)
}.disposed(by: disposeBag)

2.4 AnyObserver、Binder

2.4.1 观察者(Observer)

image

2.4.2 创建观察者

2.4.2.1 直接在 subscribe、bind 方法中创建观察者

  1. 在 subscribe 方法中创建

(1)创建观察者最直接的方法就是在 Observable 的 subscribe 方法后面描述当事件发生时,需要如何做出响应。
(2)比如下面的样例,观察者就是由后面的 onNext,onError,onCompleted 这些闭包构建出来的。

let observable = Observable.of("A", "B", "C")
          
observable.subscribe(onNext: { element in
    print(element)
}, onError: { error in
    print(error)
}, onCompleted: {
    print("completed")
})

运行结果:


image
  1. 在 bind 方法中创建
    (1)下面代码我们创建一个定时生成索引数的 Observable 序列,并将索引数不断显示在 label 标签上:
//Observable序列(每隔1秒钟发出一个索引数)
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
 
        observable
            .map { "当前索引数:\($0 )"}
            .bind { [weak self](text) in
                //收到发出的索引数后显示到label上
                self?.label.text = text
            }
            .disposed(by: disposeBag)

2.4.2.2 使用 AnyObserver 创建观察者

//观察者
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)
 //观察者
        let observer: AnyObserver<String> = AnyObserver { [weak self] (event) in
            switch event {
            case .next(let text):
                //收到发出的索引数后显示到label上
                self?.label.text = text
            default:
                break
            }
        }
         
        //Observable序列(每隔1秒钟发出一个索引数)
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        observable
            .map { "当前索引数:\($0 )"}
            .bind(to: observer)
            .disposed(by: disposeBag)
    }

2.4.2.3 使用 Binder 创建观察者

(1)相较于 AnyObserver 的大而全,Binder 更专注于特定的场景。Binder 主要有以下两个特征:
不会处理错误事件
确保绑定都是在给定 Scheduler 上执行(默认 MainScheduler)
(2)一旦产生错误事件,在调试环境下将执行 fatalError,在发布环境下将打印错误信息。

       //观察者
        let observer: Binder<String> = Binder(label) { (view, text) in
            //收到发出的索引数后显示到label上
            view.text = text
        }
         
        //Observable序列(每隔1秒钟发出一个索引数)
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        observable
            .map { "当前索引数:\($0 )"}
            .bind(to: observer)
            .disposed(by: disposeBag)

//Observable序列(每隔1秒钟发出一个索引数)
let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
    .map { $0 % 2 == 0 }
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

2.5 自定义可绑定属性

import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    @IBOutlet weak var label: UILabel!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //Observable序列(每隔0.5秒钟发出一个索引数)
        let observable = Observable<Int>.interval(0.5, scheduler: MainScheduler.instance)
        observable
            .map { CGFloat($0) }
            .bind(to: label.fontSize) //根据索引数不断变放大字体
            .disposed(by: disposeBag)
    }
}
 
extension UILabel {
    public var fontSize: Binder<CGFloat> {
        return Binder(self) { label, fontSize in
            label.font = UIFont.systemFont(ofSize: fontSize)
        }
    }
}
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    @IBOutlet weak var label: UILabel!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //Observable序列(每隔0.5秒钟发出一个索引数)
        let observable = Observable<Int>.interval(0.5, scheduler: MainScheduler.instance)
        observable
            .map { CGFloat($0) }
            .bind(to: label.rx.fontSize) //根据索引数不断变放大字体
            .disposed(by: disposeBag)
    }
}
 
extension Reactive where Base: UILabel {
    public var fontSize: Binder<CGFloat> {
        return Binder(self.base) { label, fontSize in
            label.font = UIFont.systemFont(ofSize: fontSize)
        }
    }
}

其实 RxSwift 已经为我们提供许多常用的可绑定属性。比如 UILabel 就有 text 和 attributedText 这两个可绑定属性。

extension Reactive where Base: UILabel {
     
    /// Bindable sink for `text` property.
    public var text: Binder<String?> {
        return Binder(self.base) { label, text in
            label.text = text
        }
    }
 
    /// Bindable sink for `attributedText` property.
    public var attributedText: Binder<NSAttributedString?> {
        return Binder(self.base) { label, text in
            label.attributedText = text
        }
    }
}

那么上文那个定时显示索引数的样例,我们其实不需要自定义 UI 观察者,直接使用 RxSwift 提供的绑定属性即可。

//Observable序列(每隔1秒钟发出一个索引数)
        let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
        observable
            .map { "当前索引数:\($0 )"}
            .bind(to: label.rx.text) //收到发出的索引数后显示到label上
            .disposed(by: disposeBag)

2.6 Subjects、Variables

当我们创建一个 Observable 的时候就要预先将要发出的数据都准备好,等到有人订阅它时再将数据通过 Event 发出去。
但有时我们希望 Observable 在运行时能动态地“获得”或者说“产生”出一个新的数据,再通过 Event 发送出去。比如:订阅一个输入框的输入内容,当用户每输入一个字后,这个输入框关联的 Observable 就会发出一个带有输入内容的 Event,通知给所有订阅者。
这个就可以使用下面将要介绍的 Subjects 来实现。

2.6.1 Subjects

2.6.1.1 Subjects 简介

-(1)Subjects 既是订阅者,也是 Observable:
说它是订阅者,是因为它能够动态地接收新的值。
说它又是一个 Observable,是因为当 Subjects 有了新的值之后,就会通过 Event 将新值发出给他的所有订阅者。

-(2)一共有四种 Subjects,分别为:PublishSubjectBehaviorSubjectReplaySubjectVariable。他们之间既有各自的特点,也有相同之处:

  1. 首先他们都是 Observable,他们的订阅者都能收到他们发出的新的 Event
  2. 直到 Subject 发出 .complete 或者 .errorEvent 后,该 Subject 便终结了,同时它也就不会再发出 .next 事件。
  3. 对于那些在 Subject 终结后再订阅他的订阅者,也能收到 subject 发出的一条 .complete.errorevent,告诉这个新的订阅者它已经终结了。
  4. .他们之间最大的区别只是在于:当一个新的订阅者刚订阅它的时候,能不能收到 Subject 以前发出过的旧 Event,如果能的话又能收到多少个。

-(3)Subject 常用的几个方法:

  1. onNext(:):是 on(.next(:)) 的简便写法。该方法相当于 subject 接收到一个 .next 事件。
  2. onError(:):是 on(.error(:)) 的简便写法。该方法相当于 subject 接收到一个 .error 事件。
  3. onCompleted():是 on(.completed) 的简便写法。该方法相当于 subject 接收到一个 .completed 事件。

2.6.1.2 PublishSubject

PublishSubject 是最普通的 Subject,它不需要初始值就能创建。
PublishSubject 的订阅者从他们开始订阅的时间点起,可以收到订阅后 Subject 发出的新 Event,而不会收到他们在订阅前已发出的 Event

image
let disposeBag = DisposeBag()
 
//创建一个PublishSubject
let subject = PublishSubject<String>()
 
//由于当前没有任何订阅者,所以这条信息不会输出到控制台
subject.onNext("111")
 
//第1次订阅subject
subject.subscribe(onNext: { string in
    print("第1次订阅:", string)
}, onCompleted:{
    print("第1次订阅:onCompleted")
}).disposed(by: disposeBag)
 
//当前有1个订阅,则该信息会输出到控制台
subject.onNext("222")
 
//第2次订阅subject
subject.subscribe(onNext: { string in
    print("第2次订阅:", string)
}, onCompleted:{
    print("第2次订阅:onCompleted")
}).disposed(by: disposeBag)
 
//当前有2个订阅,则该信息会输出到控制台
subject.onNext("333")
 
//让subject结束
subject.onCompleted()
 
//subject完成后会发出.next事件了。
subject.onNext("444")
 
//subject完成后它的所有订阅(包括结束后的订阅),都能收到subject的.completed事件,
subject.subscribe(onNext: { string in
    print("第3次订阅:", string)
}, onCompleted:{
    print("第3次订阅:onCompleted")
}).disposed(by: disposeBag)

运行结果:

image

2.6.1.3 BehaviorSubject

-(1)基本介绍

BehaviorSubject 需要通过一个默认初始值来创建。
当一个订阅者来订阅它的时候,这个订阅者会立即收到 BehaviorSubjects 上一个发出的 event。之后就跟正常的情况一样,它也会接收到 BehaviorSubject 之后发出的新的 event

-(2)时序图
如下图:最上面一条是 BehaviorSubject
下面两条分别表示两个新的订阅,它们订阅的时间点不同,可以发现 BehaviorSubject 的订阅者一开始就能收到 BehaviorSubjects 之前发出的一个 Event

BehaviorSubject
let disposeBag = DisposeBag()
 
//创建一个BehaviorSubject
let subject = BehaviorSubject(value: "111")
 
//第1次订阅subject
subject.subscribe { event in
    print("第1次订阅:", event)
}.disposed(by: disposeBag)
 
//发送next事件
subject.onNext("222")
 
//发送error事件
subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
 
//第2次订阅subject
subject.subscribe { event in
    print("第2次订阅:", event)
}.disposed(by: disposeBag)

运行结果:


image

2.6.1.4 ReplaySubject

  1. ReplaySubject 在创建时候需要设置一个 bufferSize,表示它对于它发送过的 event 的缓存个数。
  2. 比如一个 ReplaySubjectbufferSize 设置为 2,它发出了 3 个 .nextevent,那么它会将后两个(最近的两个)event 给缓存起来。此时如果有一个 subscriber 订阅了这个 ReplaySubject,那么这个 subscriber 就会立即收到前面缓存的两个 .nextevent
  3. 如果一个 subscriber 订阅已经结束的 ReplaySubject,除了会收到缓存的 .nextevent 外,还会收到那个终结的 .error 或者 .completeevent
ReplaySubject
let disposeBag = DisposeBag()
 
//创建一个bufferSize为2的ReplaySubject
let subject = ReplaySubject<String>.create(bufferSize: 2)
 
//连续发送3个next事件
subject.onNext("111")
subject.onNext("222")
subject.onNext("333")
 
//第1次订阅subject
subject.subscribe { event in
    print("第1次订阅:", event)
}.disposed(by: disposeBag)
 
//再发送1个next事件
subject.onNext("444")
 
//第2次订阅subject
subject.subscribe { event in
    print("第2次订阅:", event)
}.disposed(by: disposeBag)
 
//让subject结束
subject.onCompleted()
 
//第3次订阅subject
subject.subscribe { event in
    print("第3次订阅:", event)
}.disposed(by: disposeBag)

运行结果:

image

2.6.2 Variables

2.6.2.1 Variable

-(1)基本介绍

  1. Variable 其实就是对 BehaviorSubject 的封装,所以它也必须要通过一个默认的初始值进行创建。
  2. Variable 具有 BehaviorSubject 的功能,能够向它的订阅者发出上一个 event 以及之后新创建的 event
  3. 不同的是,Variable 还把会把当前发出的值保存为自己的状态。同时它会在销毁时自动发送 .completeevent,不需要也不能手动给 Variables 发送 completed 或者 error 事件来结束它。
  4. 简单地说就是 Variable 有一个 value 属性,我们改变这个 value 属性的值就相当于调用一般 SubjectsonNext() 方法,而这个最新的 onNext() 的值就被保存在 value 属性里了,直到我们再次修改它。
  5. Variables 本身没有 subscribe() 方法,但是所有 Subjects 都有一个 asObservable() 方法。我们可以使用这个方法返回这个 VariableObservable 类型,拿到这个 Observable 类型我们就能订阅它了。
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    override func viewDidLoad() {
        super.viewDidLoad()
 
        let disposeBag = DisposeBag()
         
        //创建一个初始值为111的Variable
        let variable = Variable("111")
         
        //修改value值
        variable.value = "222"
         
        //第1次订阅
        variable.asObservable().subscribe {
            print("第1次订阅:", $0)
        }.disposed(by: disposeBag)
         
        //修改value值
        variable.value = "333"
         
        //第2次订阅
        variable.asObservable().subscribe {
            print("第2次订阅:", $0)
        }.disposed(by: disposeBag)
         
        //修改value值
        variable.value = "444"
    }
}

注意:由于 Variable 对象在 viewDidLoad() 方法内初始化,所以它的生命周期就被限制在该方法内。当这个方法执行完毕后,这个 Variable 对象就会被销毁,同时它也就自动地向它的所有订阅者发出 .completed 事件

运行结果:

image

2.6.2.2 BehaviorRelay

  1. BehaviorRelay 是作为 Variable 的替代者出现的。它的本质其实也是对 BehaviorSubject 的封装,所以它也必须要通过一个默认的初始值进行创建。
  2. BehaviorRelay 具有 BehaviorSubject 的功能,能够向它的订阅者发出上一个 event 以及之后新创建的 event
  3. BehaviorSubject 不同的是,不需要也不能手动给 BehaviorReply 发送 completed 或者 error 事件来结束它(BehaviorRelay 会在销毁时也不会自动发送 .completeevent)。
  4. BehaviorRelay 有一个 value 属性,我们通过这个属性可以获取最新值。而通过它的 accept() 方法可以对值进行修改。
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        let disposeBag = DisposeBag()
         
        //创建一个初始值为111的BehaviorRelay
        let subject = BehaviorRelay<String>(value: "111")
         
        //修改value值
        subject.accept("222")
         
        //第1次订阅
        subject.asObservable().subscribe {
            print("第1次订阅:", $0)
            }.disposed(by: disposeBag)
         
        //修改value值
        subject.accept("333")
         
        //第2次订阅
        subject.asObservable().subscribe {
            print("第2次订阅:", $0)
            }.disposed(by: disposeBag)
         
        //修改value值
        subject.accept("444")
    }
}

运行结果:


image
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        let disposeBag = DisposeBag()
         
        //创建一个初始值为包含一个元素的数组的BehaviorRelay
        let subject = BehaviorRelay<[String]>(value: ["1"])
         
        //修改value值
        subject.accept(subject.value + ["2", "3"])
         
        //第1次订阅
        subject.asObservable().subscribe {
            print("第1次订阅:", $0)
            }.disposed(by: disposeBag)
         
        //修改value值
        subject.accept(subject.value + ["4", "5"])
         
        //第2次订阅
        subject.asObservable().subscribe {
            print("第2次订阅:", $0)
            }.disposed(by: disposeBag)
         
        //修改value值
        subject.accept(subject.value + ["6", "7"])
    }
}

运行结果:

image

2.7 变换操作符:buffer、map、flatMap、scan等

2.7.1 buffer

buffer 方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。
该方法简单来说就是缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来。

buffer
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
 
        let subject = PublishSubject<String>()
 
        //每缓存3个元素则组合起来一起发出。
        //如果1秒钟内不够3个也会发出(有几个发几个,一个都没有发空数组 [])
        subject
            .buffer(timeSpan: 1, count: 3, scheduler: MainScheduler.instance)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
 
        subject.onNext("a")
        subject.onNext("b")
        subject.onNext("c")
         
        subject.onNext("1")
        subject.onNext("2")
        subject.onNext("3")
    }
}

运行结果:

image

2.7.2 window

window 操作符和 buffer 十分相似。不过 buffer 是周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来。
同时 buffer 要等到元素搜集完毕后,才会发出元素序列。而 window 可以实时发出元素序列。

window
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        let subject = PublishSubject<String>()
         
        //每3个元素作为一个子Observable发出。
        subject
            .window(timeSpan: 1, count: 3, scheduler: MainScheduler.instance)
            .subscribe(onNext: { [weak self]  in
                print("subscribe: \($0)")
                $0.asObservable()
                    .subscribe(onNext: { print($0) })
                    .disposed(by: self!.disposeBag)
            })
            .disposed(by: disposeBag)
         
        subject.onNext("a")
        subject.onNext("b")
        subject.onNext("c")
         
        subject.onNext("1")
        subject.onNext("2")
        subject.onNext("3")
    }
}

运行结果:

image

2.7.3 map

map
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3)
    .map { $0 * 10}
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:
10
20
30

2.7.4 flatMap

  1. map 在做转换的时候容易出现“升维”的情况。即转变之后,从一个序列变成了一个序列的序列。
  2. flatMap 操作符会对源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。 然后将这些 Observables 的元素合并之后再发送出来。即又将其 "拍扁"(降维)成一个 Observable 序列。
  3. 这个操作符是非常有用的。比如当 Observable 的元素本生拥有其他的 Observable 时,我们可以将所有子 Observables 的元素发送出来。
flatMap
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .flatMap { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")

运行结果:

image

2.7.5 flatMapLatest

flatMapLatest
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .flatMapLatest { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")

运行结果:

image

2.7.6 flatMapFirst

  1. flatMapFirst 与 flatMapLatest 正好相反:flatMapFirst 只会接收最初的 value 事件。
  2. 该操作符可以防止重复请求:
    比如点击一个按钮发送一个请求,当该请求完成前,该按钮点击都不应该继续发送请求。便可该使用 flatMapFirst 操作符。
flatMapFirst
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .flatMapFirst { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")

运行结果:

image

2.7.7 concatMap

concatMap 与 flatMap 的唯一区别是:当前一个 Observable 元素发送完毕后,后一个Observable 才可以开始发出元素。或者说等待前一个 Observable 产生完成事件后,才对后一个 Observable 进行订阅。

concatMap
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .concatMap { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
subject1.onCompleted() //只有前一个序列结束后,才能接收下一个序列

运行结果:

image

2.7.8 scan

scan 就是先给一个初始化的数,然后不断的拿前一个结果和最新的值进行处理操作。

scan
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4, 5)
    .scan(0) { acum, elem in
        acum + elem
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果

image

2.7.9 groupBy

groupBy 操作符将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。
也就是说该操作符会将元素通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。

groupBy
let disposeBag = DisposeBag()
 
//将奇数偶数分成两组
Observable<Int>.of(0, 1, 2, 3, 4, 5)
    .groupBy(keySelector: { (element) -> String in
        return element % 2 == 0 ? "偶数" : "基数"
    })
    .subscribe { (event) in
        switch event {
        case .next(let group):
            group.asObservable().subscribe({ (event) in
                print("key:\(group.key)    event:\(event)")
            })
            .disposed(by: disposeBag)
        default:
            print("")
        }
    }
.disposed(by: disposeBag)

运行结果:

image

2.8 过滤操作符:filter、take、skip等

2.8.1 filter

该操作符就是用来过滤掉某些不符合要求的事件。

filter
let disposeBag = DisposeBag()
 
Observable.of(2, 30, 22, 5, 60, 3, 40 ,9)
    .filter {
        $0 > 10
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
image

2.8.2 distinctUntilChanged

let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 1, 1, 4)
    .distinctUntilChanged()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:

image

2.8.3 single

限制只发送一次事件,或者满足条件的第一个事件。
如果存在有多个事件或者没有事件都会发出一个 error 事件。
如果只有一个事件,则不会发出 error 事件。

single
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .single{ $0 == 2 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
Observable.of("A", "B", "C", "D")
    .single()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:

image

2.8.4 elementAt

let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .elementAt(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:
3

2.8.5 ignoreElements

该操作符可以忽略掉所有的元素,只发出 error 或 completed 事件。
如果我们并不关心 Observable 的任何元素,只想知道 Observable 在什么时候终止,那就可以使用 ignoreElements 操作符。

ignoreElements
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .ignoreElements()
    .subscribe{
        print($0)
    }
    .disposed(by: disposeBag)

运行结果:
completed

2.8.6 take

let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .take(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:
1
2

2.8.7 takeLast

let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .takeLast(1)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:
4

2.8.8 skip

let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .skip(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:
3
4

2.8.9 Sample

  1. Sample 除了订阅源 Observable 外,还可以监视另外一个 Observable, 即 notifier 。
  2. 每当收到 notifier 事件,就会从源序列取一个最新的事件并发送。而如果两次 notifier 事件之间没有源序列的事件,则不发送值。
Sample
let disposeBag = DisposeBag()
 
let source = PublishSubject<Int>()
let notifier = PublishSubject<String>()
 
source
    .sample(notifier)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
source.onNext(1)
 
//让源序列接收接收消息
notifier.onNext("A")
 
source.onNext(2)
 
//让源序列接收接收消息
notifier.onNext("B")
notifier.onNext("C")
 
source.onNext(3)
source.onNext(4)
 
//让源序列接收接收消息
notifier.onNext("D")
 
source.onNext(5)
 
//让源序列接收接收消息
notifier.onCompleted()

运行结果:

1
2
4
5

2.8.10 debounce

  1. debounce 操作符可以用来过滤掉高频产生的元素,它只会发出这种元素:该元素产生后,一段时间内没有新元素产生。
  2. 换句话说就是,队列中的元素如果和下一个元素的间隔小于了指定的时间间隔,那么这个元素将被过滤掉。
  3. debounce 常用在用户输入的时候,不需要每个字母敲进去都发送一个事件,而是稍等一下取最后一个事件。
debounce
import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
 
        //定义好每个事件里的值以及发送的时间
        let times = [
            [ "value": 1, "time": 0.1 ],
            [ "value": 2, "time": 1.1 ],
            [ "value": 3, "time": 1.2 ],
            [ "value": 4, "time": 1.2 ],
            [ "value": 5, "time": 1.4 ],
            [ "value": 6, "time": 2.1 ]
        ]
         
        //生成对应的 Observable 序列并订阅
        Observable.from(times)
            .flatMap { item in
                return Observable.of(Int(item["value"]!))
                    .delaySubscription(Double(item["time"]!),
                                       scheduler: MainScheduler.instance)
            }
            .debounce(0.5, scheduler: MainScheduler.instance) //只发出与下一个间隔超过0.5秒的元素
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
    }
}

运行结果:
1
5
6

2.9 条件和布尔操作符:amb、takeWhile、skipWhile等

2.9.1 amb

let disposeBag = DisposeBag()
 
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
let subject3 = PublishSubject<Int>()
 
subject1
    .amb(subject2)
    .amb(subject3)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject2.onNext(1)
subject1.onNext(20)
subject2.onNext(2)
subject1.onNext(40)
subject3.onNext(0)
subject2.onNext(3)
subject1.onNext(60)
subject3.onNext(0)
subject3.onNext(0)

运行结果:
1
2
3

2.9.2 takeWhile

let disposeBag = DisposeBag()
 
Observable.of(2, 3, 4, 5, 6)
    .takeWhile { $0 < 4 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:
2
3

2.9.3 takeUntil

  1. 除了订阅源 Observable 外,通过 takeUntil 方法我们还可以监视另外一个 Observable, 即 notifier
  2. 如果 notifier 发出值或 complete 通知,那么源 Observable 便自动完成,停止发送事件。
    takeUntil
let disposeBag = DisposeBag()
 
let source = PublishSubject<String>()
let notifier = PublishSubject<String>()
 
source
    .takeUntil(notifier)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
source.onNext("a")
source.onNext("b")
source.onNext("c")
source.onNext("d")
 
//停止接收消息
notifier.onNext("z")
 
source.onNext("e")
source.onNext("f")
source.onNext("g")

输出结果:
a
b
c
d

2.9.4 skipWhile

  1. 该方法用于跳过前面所有满足条件的事件。
  2. 一旦遇到不满足条件的事件,之后就不会再跳过了。


    skipWhile
let disposeBag = DisposeBag()
 
Observable.of(2, 3, 4, 5, 6)
    .skipWhile { $0 < 4 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
    }
}

运行结果:
4
5
6

2.9.5 skipUntil

  1. 同上面的 takeUntil 一样,skipUntil 除了订阅源 Observable 外,通过 skipUntil 方法我们还可以监视另外一个 Observable, 即 notifier
  2. takeUntil 相反的是。源 Observable 序列事件默认会一直跳过,直到 notifier 发出值或 complete 通知。
skipUntil
let disposeBag = DisposeBag()
 
let source = PublishSubject<Int>()
let notifier = PublishSubject<Int>()
 
source
    .skipUntil(notifier)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
source.onNext(1)
source.onNext(2)
source.onNext(3)
source.onNext(4)
source.onNext(5)
 
//开始接收消息
notifier.onNext(0)
 
source.onNext(6)
source.onNext(7)
source.onNext(8)
 
//仍然接收消息
notifier.onNext(0)
 
source.onNext(9)

运行结果:
6
7
8
9

2.10 结合操作符:startWith、merge、zip等

2.10.1 startWith

该方法会在 Observable 序列开始之前插入一些事件元素。即发出事件消息之前,会先发出这些预先插入的事件消息

let disposeBag = DisposeBag()
         
Observable.of("2", "3")
    .startWith("1")
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:

1
2
3

let disposeBag = DisposeBag()
 
Observable.of("2", "3")
    .startWith("a")
    .startWith("b")
    .startWith("c")
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

运行结果:

c
b
a
2
3

2.10.2 merge

该方法可以将多个(两个或两个以上的)Observable 序列合并成一个 Observable 序列。

let disposeBag = DisposeBag()
         
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
 
Observable.of(subject1, subject2)
    .merge()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext(20)
subject1.onNext(40)
subject1.onNext(60)
subject2.onNext(1)
subject1.onNext(80)
subject1.onNext(100)
subject2.onNext(1)

运行结果:

20
40
60
1
80
100
1

2.10.3 zip

该方法可以将多个(两个或两个以上的)Observable 序列压缩成一个 Observable 序列。
而且它会等到每个 Observable 事件一一对应地凑齐之后再合并。

let disposeBag = DisposeBag()
         
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()
 
Observable.zip(subject1, subject2) {
    "\($0)\($1)"
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)

运行结果:

1A
2B
3C
4D

比如我们想同时发送两个请求,只有当两个请求都成功后,再将两者的结果整合起来继续往下处理。这个功能就可以通过 zip 来实现。

//第一个请求
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) //加这个是应为请求在后台线程,下面的绑定在前台线程。
    .subscribe(onNext: { (user, friends) in
        //将数据绑定到界面上
        //.......
    })
    .disposed(by: disposeBag)

2.10.4 combineLatest

  1. 该方法同样是将多个(两个或两个以上的)Observable 序列元素进行合并。
  2. 但与 zip 不同的是,每当任意一个 Observable 有新的事件发出时,它会将每个 Observable 序列的最新的一个事件元素进行合并。
let disposeBag = DisposeBag()
         
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()
 
Observable.combineLatest(subject1, subject2) {
    "\($0)\($1)"
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)

运行结果:


image

2.10.5 withLatestFrom

该方法将两个 Observable 序列合并为一个。每当 self 队列发射一个元素时,便从第二个序列中取出最新的一个值。

let disposeBag = DisposeBag()
 
let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()
 
subject1.withLatestFrom(subject2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("A")
subject2.onNext("1")
subject1.onNext("B")
subject1.onNext("C")
subject2.onNext("2")
subject1.onNext("D")

运行结果:

1
1
2

2.10.6 switchLatest

  1. switchLatest 有点像其他语言的 switch 方法,可以对事件流进行转换。
  2. 比如本来监听的 subject1,我可以通过更改 variable 里面的 value 更换事件源。变成监听 subject2
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .switchLatest()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
subject1.onNext("C")
 
//改变事件源
variable.value = subject2
subject1.onNext("D")
subject2.onNext("2")
 
//改变事件源
variable.value = subject1
subject2.onNext("3")
subject1.onNext("E")

运行结果:


image

2.11

上一篇下一篇

猜你喜欢

热点阅读