RxSwift学习-09-映射操作解析

2,186 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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

image.png

它是可观察序列协议的拓展,定义了一个map的方法。这样我们的可观察序列都具备了map的方法,该方法最后返回一个可观察序列。继续点击查看Map(source: self.asObservable(), transform: transform)

image.png

Map类初始化保存了源序列喝我们map的闭包transform。此时Map类也是继承于Producer因此具有subscribe的能力。这里流程和之前分析一样,在订阅的时候会进入Producer的subscribe方法

image.png 第一次进入需要进行绑定线程的调度环境,关于调度后面的文章会进行分析。这里会走序列的run方法,我们的Map.run这里穿入的观察者就是我们订阅的时候创建的匿名观察者AnonymousObserver,之前文章有分析过核心逻辑。

image.png 继续查看

image.png 正常我们这里会执行sink.run,但是这里游再次通过源可观察序列进行subscribe订阅。这里会走我们之前分析的订阅流程

image.png 我们的源序列是通过便捷方法from创建的,因此源可观察序列为ObservableSequence类型

image.png

因此我们查看ObservableSequencerun方法

image.png

通过管子sink关联观察者和序列,observer为我们保存transform闭包MapSink,查看管子的run方法。

image.png 可以发现里面有个迭代器,这里的parent为我们开始时时候源序列,我们继续走 forwardOn

image.png

这里的observer为mapsink 因此我们去查看mapSink的on方法

image.png 这里会把我们保存的transform闭包进行调用,之后在进行forwardOn事件。

image.png 进入父类sink的forwardOn方法,此时next事件中我们的元素从Int类型转换成了string类型。此时我们的observer为我们订阅的时候创建的匿名观察者

image.png 进入序列的onCore方法

image.png

最后调用匿名观察者的事件闭包

image.png

2. flatMap

flatMap在Swift的高阶函数是

image.png 可以看到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)


image.png 我们看下它的核心逻辑

image.png 保存我们的源序列和我们flatMap转换的闭包(该闭包返回的是一个可观察序列)。 同样的我们订阅的时候会进入run方法,因为我们的FlatMapSink继承于MergeSink因此sink.run会进入mergeSink的run方法中

image.png

我们的源序列进行订阅传入的是我们的FlatMapSink,这里会走我们soucre序列的订阅方法,此时我们的序列为BehaviorRelay

image.png

这里结合你自身源序列的类型,走对应的subscribe方法。我们的FlatMapSink没有on方法,我们去它的父类查找。

image.png

这里就是核心

image.png

这里是调用子类的performMap,也就是FlatMapSink的具体实现返回一个新的可观察序列

image.png

进行内部订阅

image.png

之后新的序列进行事件发送

image.png

进行回调。

3. 总结

对于映射操作Map我们,这里就介绍这2种,具体情况还是要自己打断点分析分析。

  • map 其实来说就是对于我们的可观察序列的元素element是数组的时候,我们通过map保存了一个闭包,当发送信号的时候,会经过一层transform闭包的回调处理我们的发送元素element,之后进行eventHanlde到订阅者的回调。

未命名文件-7.jpg

  • Flatmap 对于FlatMap其实我们从底层来说也是类似,我们不再转换元素而是转换了序列源,我们的序列相当一个中间层,当源序列发生改变,我们的订阅的内容也随之发生改变,相当于一个转接头

未命名文件-8.jpg