转换运算符:地图,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非常常用于诸如网络之类的异步操作。
我们阅读了三个变换运算符,并看到了地图运算符的作用。现在,我们将与flatMap和flatMapLatest一起使用,并了解如何在代码库中实现这些运算符。 让我们从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 。 因此, currentPlayer是GamePlayer的 Observable,它具有playerScore Observable属性。 我们要订阅currentplayer的playerScore 。 请记住,我们需要首先调用asObservable()来处理Variable的可观察主题值,因为Variable是BehaviorSubject的包装。 刚才,我们提到了flatMap和flatMapLatest允许我们进入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并将其最新或初始元素重放给新订阅者,因此该值被打印出来:
我们将更新currentPlayer的playerScore的值:
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