RxSwift-转换(Transforming)操作符
· 8 min read
本文主要介绍了一些转换功能的操作符, 并且引入一些例子便于开发者快速理解和应用它们.
先介绍如下几种具有转换功能的操作符:
-
toArray: 将序列中的元素装入一个数组, 作为新序列的一个元素
-
map 操作符: 映射操作, 和 swift 集合中的同理.
-
flatMap 族操作符: 类似 swift 中的集合上可以进行的 flatMap, 即平铺映射.
可以将由 Observable 组成的序列中的每个 Observable 都展开, 然 后合并到一个 Observable 上.
如果这些作为元素的 Observable 序列有新的事件, 则观察者也会被通知到. 总而言之, 就是 flatMap 总是会将每个子序列中的任何改变送入新序列.
这个行为可以很好地被用在网络请求中, 在网络请求操作序列上直接应用 flatMap, 也可以达到 "等待" 下一个元素的效果.(实际就是当下一个元素到达时, 订阅者可以收到这些事件, 而非真的去等待事件到达.)
- flatMapLatest 操作符: 可以进行平铺映射
和 flatMap 相比, 它的一个巨大不同是: 当有多个子 Observable 序列时, 它会自动将订阅切换到最后一个产生事件的序列上.
这里的最后一个发射的序列是指: 在原始的 Observable 上的最新的那个作为元素的子序列.
这个操作符在网络请求上十分常用, 比如用户搜索时, 将每个搜索的网络请求都作为一个子序列放到原始序列中, 这样的话, 订阅者可以自动切换到最新的搜索上, 而不用去管之前的结果.
- materialize 操作符: 将序列中的事件包裹起来, 原样呈现给订阅者, 而非事件中包含的元素, 这样就可以提前对子序列中的事件进行处理.
它非常适用于对子序列没有直接控制的情况.(比如网络请求操作...)
- dematerialize: 将序列中的事件包含重新转换为元素, 作用和 materialize 正好相反.
示例代码如下所示:
func transformingOperatorIntro() {
/*
1. toArray: 将序列中的元素装入一个数组, 作为新序列的一个元素
*/
exampleOf(msg: "toArray 操作符", action: { bag in
Observable.of("a", "b", "c")
.toArray()
.subscribe(onNext: {
print($0)
print(type(of: $0))
}, onError: { print($0) },
onCompleted: { print("完成") },
onDisposed: { print("被释放")})
.disposed(by: bag)
})
/*
2. map 操作符: 映射操作, 和 swift 集合中的同理.
*/
exampleOf(msg: "map 操作符", action: { bag in
Observable.of(1, 2, 3, 4, 5)
.map({ "元素 \($0 * 2)" })
.subscribe(onNext: {
print($0)
}).disposed(by: bag)
})
/*
3. flatMap 族操作符: 类似 swift 中的集合上可以进行的 flatMap, 即平铺映射.
可以将由 Observable 组成的序列中的每个 Observable 都展开, 然后合并到一个 Observable 上.
如果这些作为元素的 Observable 序列有新的事件, 则观察者也会被通知到.
总而言之, 就是 flatMap 总是会发射每个子序列中的任何改变.
这个行为可以很好地被用在网络请求中, 在网络请求序列上直接应用 flatMap, 也可以达到 "等待" 下一个元素的效果.
(实际就是当下一个元素到达时, 订阅者可以收到这些事件)
*/
exampleOf(msg: "flatMap 族操作符", action: { bag in
struct Student {
var score: BehaviorSubject<Int>
}
let stu1 = Student(score: BehaviorSubject<Int>(value: 80))
let stu2 = Student(score: BehaviorSubject<Int>(value: 95))
let pub = PublishSubject<Student>()
pub.flatMap({ $0.score }).subscribe(onNext: {
print("成绩: \($0)")
}).disposed(by: bag)
pub.onNext(stu1)
pub.onNext(stu2)
stu1.score.onNext(99)
})
/*
4. flatMapLatest 操作符: 可以进行平铺映射
它的一个巨大不同是: 当有多个子 Observable 序列时, 它会自动将订阅切换到最后一个产生事件的序列上.
可以看到和之前的 flatMap 最大的不同是: 它在平铺映射的同时, 还进行了切换操作, 将订阅切换到最后一个发射的序列上.
这里的最后一个发射的序列是指: 在原始的 Observable 上的最新的那个作为元素的子序列.
故上述代码中, 订阅会一直订阅的是 stu2, 因为 stu2 是最新的一个子序列.
这个操作符在网络请求上仍然十分常用, 比如用户搜索时, 将每个搜索的网络请求都作为一个子序列放到原始序列中, 这样的话,
订阅者可以自动切换到最新的搜索上, 而不用去管之前的结果.
*/
exampleOf(msg: "flatMapLatest 族操作符", action: { bag in
struct Student {
var score: BehaviorSubject<Int>
}
let stu1 = Student(score: BehaviorSubject<Int>(value: 80))
let stu2 = Student(score: BehaviorSubject<Int>(value: 95))
let pub = PublishSubject<Student>()
pub.flatMapLatest({ $0.score }).subscribe(onNext: {
print("成绩: \($0)")
}).disposed(by: bag)
pub.onNext(stu1)
pub.onNext(stu2)
stu1.score.onNext(99)
stu2.score.onNext(15)
stu1.score.onNext(70)
})
/*
5. materialize 操作符: 将序列中的事件原样呈现给订阅者, 而非事件中包含的元素.
非常适用于对子序列没有直接控制的情况.(比如网络请求操作...)
*/
exampleOf(msg: "materialize 操作符: ", action: { bag in
enum MyError: Error {
case badScore
case unknown
}
struct Student {
var score: BehaviorSubject<Int>
}
let stu1 = Student(score: BehaviorSubject<Int>(value: 80))
let stu2 = Student(score: BehaviorSubject<Int>(value: 95))
let pub = PublishSubject<Student>()
pub.flatMapLatest({
// 应用了 materialize, 则可以在 next 观察中对子序列的事件进行对应处理.
$0.score.materialize()
}).subscribe(onNext: {
switch $0 {
case .next(let elem):
print("成绩: \(elem)")
case .error(let error):
print("子序列出错: \(error)")
case .completed:
print("子序列完成")
}
}, onError: {
print($0)
}).disposed(by: bag)
pub.onNext(stu1)
pub.onNext(stu2)
stu1.score.onNext(99)
stu2.score.onError(MyError.badScore)
stu2.score.onNext(15)
// 不会收到
stu1.score.onNext(70)
})
/*
6. dematerialize: 将序列中的事件包含重新转换为元素.
*/
exampleOf(msg: "dematerialize 操作符", action: { bag in
enum MyError: Error {
case badScore
case unknown
}
struct Student {
var score: BehaviorSubject<Int>
}
let stu1 = Student(score: BehaviorSubject<Int>(value: 80))
let stu2 = Student(score: BehaviorSubject<Int>(value: 95))
let pub = PublishSubject<Student>()
pub.flatMapLatest { $0.score.materialize() }.filter({
// 将子序列中的 error 先进行处理
guard $0.error == nil else {
print($0.error.debugDescription)
return false
}
return true
})
.dematerialize() // 反向处理, 将元素复原.
.subscribe(onNext: {// 这样就不需要再在订阅时使用 switch 来判断了
print($0)
}, onError: {
print($0)
}).disposed(by: bag)
pub.onNext(stu1)
pub.onNext(stu2)
stu1.score.onNext(99)
stu2.score.onError(MyError.badScore)
stu2.score.onNext(15)
// 不会收到
stu1.score.onNext(70)
})
}