16.15为什么RxSwift也需要flatMap

flatMap是个不太讨人喜欢的名字,因为集合里用它,Optional里用它,到了RxSwift里也用它,但是在这些不同的领域里,flatMap又都表达了不同的具体含义。你似乎很难简单的用一句话描述它要完成的功能。于是,如果你去看看flatMap在Rx里的定义,会发现是这样的:

Transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable.

我敢说,如果你不是之前就理解flatMap的用法,几乎很难理解它究竟要表达什么。实际上,如果把flatMap的定义拆成两部分,就容易理解多了。

把序列中的事件变成新的Observable

首先,来看flatMap定义的前半句:Transform the items emitted by an Observable into Observables。如何把序列发生的事件变成新的Observable呢?我们来看RxSwift官方提供的例子:

struct Player {
    var score: Variable<Int>
}

let John = Player(score: Variable(70))
let Jole = Player(score: Variable(90))

这样,JohnJole就是两个独立的Observable。接下来,我们创建一个PublishSubject<Player>,然后订阅它:

let players = PublishSubject<Player>()

players.asObservable()
    .flatMap {
        $0.score.asObservable()
    }
    .subscribe(onNext: {
        print($0)
    })
    .addDisposableTo(bag)

这时,我们把John加入到游戏:

players.onNext(John)

执行一下,就可以在控制台看到John的分数70了。然后,我们改变John的分数:

John.score.value = 75
John.score.value = 80

控制台上就会打印出“70 75 80”这样的结果。用序列图表示是这样的:

transform-op

其中,Johnplayer序列中发生的事件,通过flatMap我们把它变成了一个Observable<Int>。这就是flatMap定义前半句的含义:Transform the items emitted by an Observable into Observables

合成所有转换过的序列

接下来,来看flatMap定义的后半句:then flatten the emissions from those into a single Observable。为了理解这个flatten的过程,我们把Jole也添加进来,这里要特别注意Jole添加进来的位置

players.onNext(John)

John.score.value = 75
players.onNext(Jole)
John.score.value = 80

先执行一下,会看到“70 75 90 80”这样的结果。然后,我们结合序列图,来看下为什么会这样:

transform-op

首先,flatMap会把它原序列中的每个事件,都变换成一个Observable。因此,再加入了Jole之后,flatMap一共变换出了两个Observable<Int>,这就是我们之前讲过的flatMap定义的前半部分。

其次,当我们在75和80之间加入Jole的时候,flatMap会把Jole中事件的值和John中事件的值合并到一起,变成一个Observable<Int>,这种把两个Observable<Int>变成一个的过程,就是flatMap定义中,flatten的含义。

实际上,经过flatMap合并过的Observable<Int>会按发生的顺序,反映JohnJole中的所有事件。

flatMapLatest

另外一个和flatMap类似的operator是flatMapLatest。当原序列中有新事件发生的时候,flatMapLatest就会自动取消上一个事件的订阅,然后转换到新事件的订阅。而flatMap则会保持原序列中的所有事件订阅。

可能这么说有点儿抽象,我们把之前的例子用flatMapLatest来试一下:

players.asObservable()
    .flatMapLatest {
        $0.score.asObservable()
    }
    .subscribe(onNext: {
        print($0)
    })
    .addDisposableTo(bag)

同样是这样的事件顺序:

players.onNext(John)

John.score.value = 75
players.onNext(Jole)
John.score.value = 80

这次,我们会得到“70 75 90”这样的结果,也就是说,players发生Jole事件之后,flatMapLatest就取消了对John的订阅,用序列图表示,就是这样的:

transform-op

What's next?

在结束这一节的内容之前,我们不妨思考一个问题。在什么情况下需要使用flatMap呢?为什么要把一个序列中的事件,变成另外一个事件序列呢?

简单来说,因为现实中很多事件都是异步发生的,而并不是像Observable.of创建的看起来像集合这样的。因此,当我们需要对异步发生的事件序列进行变换的时候,就需要订阅原来的事件序列,对异步发生的事件有所察觉。其中,网络编程就是一个最典型的例子。为了在请求一个网络资源后,根据服务器返回的结果对原事件序列进行变换,flatMap就是最好的选择。而这,就是我们接下来两节的内容。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Introduction: Creating and Subscribing to Observables: Th...
    loongod阅读 718评论 0 0
  • RxJava详解(一) 年初的时候就想学习下RxJava然后写一些RxJava的教程,无奈发现已经年底了,然而我还...
    CharonChui阅读 2,356评论 0 0
  • 最近在学习RxSwift相关的内容,在这里记录一些基本的知识点,以便今后查阅。 Observable 在RxSwi...
    L_Zephyr阅读 1,700评论 1 4
  • 响应式编程简介 响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者...
    长夜西风阅读 3,001评论 0 5
  • 本文档内容来自于 RxSwift 的 Playground。记录大多数 ReactiveX 的概念和操作符。 Gi...
    傅坦坦阅读 1,231评论 0 5