Subject的概念和简单创建
Subject起的作用类似于bridge或者proxy, 它同时扮演观察者和被观察者. 又能发送信号, 又能接收信号.
创建Subject
let subject = PublishSubject<String>()
//添加subscribe的closure
subject.subscribe({ (event) in
//do sth
}).addDisposableTo(disposeBag)
//发送next
subject.onNext("🐶")
Subject的种类
ReplaySubject会在添加新的subscriber的时候给它发送之前的信号
let subject = ReplaySubject<String>.create(bufferSize: 1)
这里的bufferSize指的是发送最近的几个信号, 1就是只发送之前的一个.
BehaviourSubject相当于上一个bufferSize = 1.
let subject = BehaviorSubject(value: "🔴")
这样的设定比较适合那种一开始需要一个初始值的模块接收信号, 有一点需要注意的是, 所有的Subject都不会自己发送complete事件.
BehaviourSubject
有一个Wrapper叫Variable
, 和subject不同的是, 它在deinit的时候回自动发complete事件:
let variable = Variable("🔴")
variable.asObservable().addObserver("1").addDisposableTo(disposeBag)
合并Subject
StartWith
StartWith(:)
用last-in-first-out规则, 插入信号.
Observable.of("🐶", "🐱", "🐭", "🐹")
.startWith("1")
.startWith("2")
.startWith("3", "A", "B")
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
输出: 3, A, B, 2, 1, 🐶, 🐱, 🐭, 🐹
Merge
merge(: )
把两个Subject合并:
Observable.of(subject1, subject2)
.merge()
subscribe上merge()
出来的Observable的话, 会同时接收到两个subject发出的信号, 相当于同时observable了subject1和subject2.
Zip
zip(:)
让同样是组合信号, 但它是一种母信号集合为基础的组合.
Observable.zip(stringSubject, intSubject) { stringElement, intElement in
return "\(stringElement) \(intElement)"
}
subscribe了zip出来的信号的话, 接收到的是各个信号源从subscribe的时刻开始算起相同index的值组合的结果.
值得一提的是, 如果observable1发出了信号, observable2没发出, 那么zip出来的Observable并不会发出信号, 只有当observable2发出了, zip出来的Observable才会感应到并且往下派送信号.
我觉得这非常适合做那种异步集合操作, 比如说我要异步下载image1, image2, image3, 我需要系统在这三张图都下载好的时候给我发送一个提示, 用zip的话, 很方便就能拿到这样一个信号了.
CombineLatest
Combine类似Zip, 区别在它每次向下级发送信号的时候, 母Observable的值取最近的一个.
Observable.combineLatest(stringSubject, intSubject) { stringElement, intElement in
"\(stringElement) \(intElement)"
}
这种组合的应用场景我想到的有游戏里面的一些状态的刷新机制, Subject1之前的值都没有意义, 只要最新的值. 而Subject2一旦触发传递信号, 就会触发某个事件, 这个事件读取当前subject1和subject2的信息, 对应的就是往下一级发送信号.
combineLatest
有一个Array的拓展:
let stringObservable = Observable.just("❤")
let fruitObservable = ["🍎", "🍐", "🍊"].toObservable()
let animalObservable = Observable.of("🐶", "🐱", "🐭", "🐹")
[stringObservable, fruitObservable, animalObservable].combineLatest {
"\($0[0]) \($0[1]) \($0[2])"
}
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
输出:
❤ 🍊 🐶
❤ 🍊 🐱
❤ 🍊 🐭
❤ 🍊 🐹
监听切换
添加这一行 switchLatest()
当Observable的内核变化的时候, 观察者自动切换监听的对象.
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "⚽️")
let subject2 = BehaviorSubject(value: "🍎")
let variable = Variable(subject1)
variable.asObservable()
.switchLatest()
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
subject1.onNext("🏈")
subject1.onNext("🏀")
variable.value = subject2
subject1.onNext("⚾️")
subject2.onNext("🍐")
输出:
⚽️
🏈
🏀
🍎
🍐
通过variable做这样的操作, 我想象之中是可以做偷换信号源的功能. 比如, 对某一个API, retrieve data的方式是一样的, 我没必要重新写一遍subscriber的实现代码, 偷换一下从服务器Fetch数据的信号源就可以了.
Referece:
https://github.com/ReactiveX/RxSwift/tree/master/Rx.playground
https://github.com/ReactiveX/RxSwift/tree/master/Documentation
网友评论