一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情。
本文主要介绍在RxSwift中映射操作map原理解析,
关于swift中的map可以看下之前的文章 swift的数组Swift中高阶函数的使用。本质上来说就是通过便利进行trasform转换,得到一个新的结构。
1. map
我们先看下我们使用RxSwift把我们数组里的元素转换为字符串类型
let disposeBag = DisposeBag()
let ob = Observable.from([1,2,3])
ob.map{"\($0)"}
.subscribe(onNext: {print($0.description)})
.disposed(by:disposeBag )//打印结果字符串1,2,3
我们看下里面的实现,点击查看map
它是可观察序列协议的拓展,定义了一个map的方法。这样我们的可观察序列都具备了map的方法,该方法最后返回一个可观察序列。继续点击查看Map(source: self.asObservable(), transform: transform)
Map类初始化保存了源序列喝我们map的闭包transform。此时Map类也是继承于Producer因此具有subscribe的能力。这里流程和之前分析一样,在订阅的时候会进入Producer的subscribe方法
第一次进入需要进行绑定线程的
调度环境,关于调度后面的文章会进行分析。这里会走序列的run方法,我们的Map.run这里穿入的观察者就是我们订阅的时候创建的匿名观察者AnonymousObserver,之前文章有分析过核心逻辑。
继续查看
正常我们这里会执行
sink.run,但是这里游再次通过源可观察序列进行subscribe订阅。这里会走我们之前分析的订阅流程
我们的源序列是通过便捷方法
from创建的,因此源可观察序列为ObservableSequence类型
因此我们查看ObservableSequence的run方法
通过管子sink关联观察者和序列,observer为我们保存transform闭包的MapSink,查看管子的run方法。
可以发现里面有个迭代器,这里的parent为我们开始时时候源序列,我们继续走
forwardOn
这里的observer为mapsink 因此我们去查看mapSink的on方法
这里会把我们保存的
transform闭包进行调用,之后在进行forwardOn事件。
进入父类sink的
forwardOn方法,此时next事件中我们的元素从Int类型转换成了string类型。此时我们的observer为我们订阅的时候创建的匿名观察者
进入序列的
onCore方法
最后调用匿名观察者的事件闭包
2. flatMap
flatMap在Swift的高阶函数是
可以看到
flatMap是把数组中的数组进行了压平的操作,相当于二维数组转换为一维的数组。
那么在RxSwift中时如何呢?
flatMap 操作符将源 Observable 的每一个信号应用一个转换方法,将他们转换成 Observables。 然后将这些 Observables 的信号合并之后再发送出来。
//结构体
struct Player {
let score: BehaviorRelay<Int>
init(score:Int) {
self.score = BehaviorRelay(value: score)
}
}
let playerA = Player.init(score: 20)
let playerB = Player.init(score: 30)
let player = BehaviorRelay(value: playerA)
player.asObservable()
.flatMap { (player:Player) ->Observable<Int> in
player.score.asObservable()
}.subscribe { (num) in
print(num)
} onError: { (error) in
print(error)
} onCompleted: {
print("completed")
} onDisposed: {
print("disposed")
}.disposed(by: disposBag)
playerA.score.accept(40)
playerB.score.accept(50)
player.accept(playerB)
playerB.score.accept(60)
playerA.score.accept(70)
我们看下它的核心逻辑
保存我们的源序列和我们
flatMap转换的闭包(该闭包返回的是一个可观察序列)。
同样的我们订阅的时候会进入run方法,因为我们的FlatMapSink继承于MergeSink因此sink.run会进入mergeSink的run方法中
我们的源序列进行订阅传入的是我们的FlatMapSink,这里会走我们soucre序列的订阅方法,此时我们的序列为BehaviorRelay
这里结合你自身源序列的类型,走对应的subscribe方法。我们的FlatMapSink没有on方法,我们去它的父类查找。
这里就是核心
这里是调用子类的performMap,也就是FlatMapSink的具体实现返回一个新的可观察序列
进行内部订阅
之后新的序列进行事件发送
进行回调。
3. 总结
对于映射操作Map我们,这里就介绍这2种,具体情况还是要自己打断点分析分析。
- map
其实来说就是对于我们的可观察序列的元素
element是数组的时候,我们通过map保存了一个闭包,当发送信号的时候,会经过一层transform闭包的回调处理我们的发送元素element,之后进行eventHanlde到订阅者的回调。
- Flatmap
对于
FlatMap其实我们从底层来说也是类似,我们不再转换元素而是转换了序列源,我们的序列相当一个中间层,当源序列发生改变,我们的订阅的内容也随之发生改变,相当于一个转接头。