转换运算符:地图,flatMap和flatMapLatest

RxSwift提供了一系列运算符,它们可以极大地控制您要如何处理应用程序中的数据和事件。

当您要对来自序列的数据进行建模以适合您的需求时,可以使用转换运算符。 换句话说,准备数据以符合订户的要求。

例如,要转换从Observable序列发出的元素,可以使用map运算符; 当元素从源Observable序列发出时,map将对其进行变换。 这类似于标准Swift库中的map(_ 🙂方法,不同之处在于此地图可用于Observable序列元素。 地图运算符的大理石图表示将如下所示:


实际地图(_ 🙂

我们将举一个在操场上使用地图的例子。 我们将需要我们的辅助函数,即executeProcedure(with description:String,procedure:()-> Void) 。 此函数有两个参数:字符串描述和过程闭包。 然后打印说明,然后执行该过程。

 公共函数executeProcedure(用于描述:字符串,过程:()->无效){ 
print(“执行程序:”,描述)
程序()
}

现在,我们将使用of运算符创建一个Observable整数序列:

  executeProcedure(for:“ map”){ 
Observable.of(10,20,30)
}

然后,我们将使用map运算符将每个整数元素自身相乘:

  Observable.of(10,20,30) 
.map {$ 0 * $ 0}

然后,我们将订阅onNext来打印每个转换后的元素:

  Observable.of(10,20,30) 
.map {$ 0 * $ 0}
.subscribe(onNext:{
打印($ 0)
})

之后,我们对subscribe(onNext 🙂的返回值调用dispose() 。 请记住,订阅将返回Disposable 。 该函数的总体代码如下:

  executeProcedure(for:“ map”){ 
Observable.of(10,20,30)
.map {$ 0 * $ 0}
.subscribe(onNext:{
打印($ 0)
})
.dispose()
}

这将输出预期的结果,您可以在控制台中检查该结果:


一个Observable序列本身可以具有您要订阅的Observable属性。 flatMap可用于进入一个Observable序列,以与其Observable序列一起工作。 在以下示例中,01、02、03是可观察序列; flatMap会将每个序列的发射变平为单个序列,并对每个元素进行转换:

还有一个flatMapLatest运算符。 这是您要了解的一种,因为您将大量使用此运算符。

flatMap和flatMapLatest之间的区别在于,flatMapLatest将仅从最新的Observable序列中生成元素,因此,当Observable序列发出新的Observable序列时,flatMapLatest切换到该新的Observable序列,并忽略前一序列的发射。

在下图中所示的示例中,当02序列发出元素“ 2”时,现在将忽略01,因为02是最新序列。 结果,当01发出元素“ 3”时,将其忽略。 类似地,当03开始发射时,从元素“ 4”开始,它变为活动序列,而02被忽略。 因此,当02发出元素“ 5”时,它将被忽略:

flatMapLatest非常常用于诸如网络之类的异步操作


我们阅读了三个变换运算符,并看到了地图运算符的作用。现在,我们将与flatMapflatMapLatest一起使用,并了解如何在代码库中实现这些运算符。 让我们从flatMap开始。

首先,我们将声明一个具有PlayerScore属性的GamePlayer结构,该属性是Int类型的Variable事件。 我们还将声明一个disposeBag,如​​下所示:

  executeProcedure(用于:“ flatMap和flatMapLatest”){ 

struct GamePlayer {
让playerScore:变量
}
让disposeBag = DisposeBag()
}

接下来,让我们声明几个GamePlayer实例,alex和gemma,以及一个当前玩家,该玩家也是Variable ,其初始值为alex:

 让alex = GamePlayer(playerScore:Variable(70)) 
让gemma = GamePlayer(playerScore:变量(85))

var currentPlayer = Variable(alex)

我们应该指出currentPlayer是Variable 类型 ; 您可以通过Option +单击currentPlayer实例来查看此内容,如下所示:

可以从其初始值推断出currentPlayer变量的dataType 。 因此, currentPlayerGamePlayer的 Observable,它具有playerScore Observable属性。 我们要订阅currentplayerplayerScore 。 请记住,我们需要首先调用asObservable()来处理Variable的可观察主题值,因为VariableBehaviorSubject的包装。 刚才,我们提到了flatMapflatMapLatest允许我们进入Observable来访问其observable属性。 让我们看看实际情况; 我们将首先使用flatMap 。 我们将进入一个GamePlayer实例元素,访问其playerScore Variable并获取其Observable主题值:

  currentPlayer.asObservable() 
.flatMap {$ 0.playerScore.asObservable()}

现在,订阅该可观察对象并打印出来:

  currentPlayer.asObservable() 
.flatMap {$ 0.playerScore.asObservable()}
.subscribe(onNext:{
打印($ 0)
})

最后,将订阅添加到disposeBag:

  currentPlayer.asObservable() 
.flatMap {$ 0.playerScore.asObservable()}
.subscribe(onNext:{
打印($ 0)
})
.disposed(作者:disposeBag)

由于Variable包装了BehaviorSubject并将其最新或初始元素重放给新订阅者,因此该值被打印出来:

我们将更新currentPlayerplayerScore的值:

  currentPlayer.value.playerScore.value = 90 

然后,该值被打印出来:

重要的是要意识到我们特别订阅alex的分数,因为currentPlayer的值当前是alex。 因此,我们也可以向alex.playerScore添加一个新值:

  alex.playerScore.value = 95 

我们的订阅将打印出该值,如下所示:

让我们将gemma添加到我们的currentPlayer实例并监视更改:

  currentPlayer.value =宝石 

您将注意到,订阅现在将相应地打印这些值。 也就是说,gemma的分数将被打印:

您能猜出我们订阅alex的playerScore发生了什么吗? 让我们找出答案; 我们将直接向alex.playerScore.value添加一个新值:

  alex.playerScore.value = 96 

然后,您会注意到它也打印在控制台中:

这是因为flatMap不会取消订阅先前的序列。 因此,在使用flatMap时要当心 。 如果使用flatMap ,则可能会保留大量不需要的订阅,并且这些nextEvent处理程序将执行您不想要执行的操作或不再想要执行的操作。

另一方面, flatMapLatest将取消订阅先前的序列,订阅新序列,并且仅从最新序列中产生值。 让我们看一下到目前为止我们为flapMap编写的代码:

  executeProcedure(用于:“ flatMap和flatMapLatest”){ 

struct GamePlayer {
让playerScore:变量
}
让disposeBag = DisposeBag()

让alex = GamePlayer(playerScore:Variable(70))
让gemma = GamePlayer(playerScore:变量(85))

var currentPlayer = Variable(alex)

currentPlayer.asObservable()
.flatMap {$ 0.playerScore.asObservable()}
.subscribe(onNext:{
打印($ 0)
})
.disposed(作者:disposeBag)

currentPlayer.value.playerScore.value = 90
alex.playerScore.value = 95

currentPlayer.value =宝石

alex.playerScore.value = 96
}

代码的输出是这样的:

现在,让我们在前面的代码中将 flatMap更改为flatMapLatest

  executeProcedure(用于:“ flatMap和flatMapLatest”){struct GamePlayer { 
让playerScore:变量
}
让disposeBag = DisposeBag()

让alex = GamePlayer(playerScore:Variable(70))
让gemma = GamePlayer(playerScore:变量(85))

var currentPlayer = Variable(alex)

currentPlayer.asObservable()
.flatMapLatest {$ 0.playerScore.asObservable()}
.subscribe(onNext:{
打印($ 0)
})
.disposed(作者:disposeBag)

currentPlayer.value.playerScore.value = 90
alex.playerScore.value = 95

currentPlayer.value =宝石

alex.playerScore.value = 96
}

请注意,我们不再收到有关Alex的新事件。 因此,不会添加我们添加到alex.playerScore.value的96:

RxSwift中还有其他一些转换运算符,我将在下一个博客中介绍它们。


对于其他更新,您可以在我的Twitter句柄@NavRudraSambyal的Twitter上关注我。

要深入了解Rx概念和RxSwift,可以单击我的书《 Swift 4中的反应式编程》的链接

感谢您的阅读,如果发现有用,请分享share