RxSwift-转换(Transforming)操作符系列之 1

本文最后更新于 2021年4月4日 晚上

本文主要介绍了一些转换功能的操作符, 并且引入一些例子便于开发者快速理解和应用它们.

先介绍如下几种具有转换功能的操作符:

  1. toArray: 将序列中的元素装入一个数组, 作为新序列的一个元素

  2. map 操作符: 映射操作, 和 swift 集合中的同理.

  3. flatMap 族操作符: 类似 swift 中的集合上可以进行的 flatMap, 即平铺映射.

可以将由 Observable 组成的序列中的每个 Observable 都展开, 然后合并到一个 Observable 上.

如果这些作为元素的 Observable 序列有新的事件, 则观察者也会被通知到. 总而言之, 就是 flatMap 总是会将每个子序列中的任何改变送入新序列.

这个行为可以很好地被用在网络请求中, 在网络请求操作序列上直接应用 flatMap, 也可以达到 “等待” 下一个元素的效果.(实际就是当下一个元素到达时, 订阅者可以收到这些事件, 而非真的去等待事件到达.)

  1. flatMapLatest 操作符: 可以进行平铺映射

和 flatMap 相比, 它的一个巨大不同是: 当有多个子 Observable 序列时, 它会自动将订阅切换到最后一个产生事件的序列上.

这里的最后一个发射的序列是指: 在原始的 Observable 上的最新的那个作为元素的子序列.

这个操作符在网络请求上十分常用, 比如用户搜索时, 将每个搜索的网络请求都作为一个子序列放到原始序列中, 这样的话, 订阅者可以自动切换到最新的搜索上, 而不用去管之前的结果.

  1. materialize 操作符: 将序列中的事件包裹起来, 原样呈现给订阅者, 而非事件中包含的元素, 这样就可以提前对子序列中的事件进行处理.

它非常适用于对子序列没有直接控制的情况.(比如网络请求操作…)

  1. dematerialize: 将序列中的事件包含重新转换为元素, 作用和 materialize 正好相反.

示例代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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)
})
}

RxSwift-转换(Transforming)操作符系列之 1
https://blog.rayy.top/2018/11/25/2019-22-rx-transforming-intro/
作者
貘鸣
发布于
2018年11月25日
许可协议