本文最后更新于 2021年4月4日 晚上
本文主要介绍了一些转换功能的操作符, 并且引入一些例子便于开发者快速理解和应用它们.
先介绍如下几种具有转换功能的操作符:
toArray: 将序列中的元素装入一个数组, 作为新序列的一个元素
map 操作符: 映射操作, 和 swift 集合中的同理.
flatMap 族操作符: 类似 swift 中的集合上可以进行的 flatMap, 即平铺映射.
可以将由 Observable 组成的序列中的每个 Observable 都展开, 然后合并到一个 Observable 上.
如果这些作为元素的 Observable 序列有新的事件, 则观察者也会被通知到. 总而言之, 就是 flatMap 总是会将每个子序列中的任何改变送入新序列.
这个行为可以很好地被用在网络请求中, 在网络请求操作序列上直接应用 flatMap, 也可以达到 “等待” 下一个元素的效果.(实际就是当下一个元素到达时, 订阅者可以收到这些事件, 而非真的去等待事件到达.)
flatMapLatest 操作符: 可以进行平铺映射
和 flatMap 相比, 它的一个巨大不同是: 当有多个子 Observable 序列时, 它会自动将订阅切换到最后一个产生事件的序列上.
这里的最后一个发射的序列是指: 在原始的 Observable 上的最新的那个作为元素的子序列.
这个操作符在网络请求上十分常用, 比如用户搜索时, 将每个搜索的网络请求都作为一个子序列放到原始序列中, 这样的话, 订阅者可以自动切换到最新的搜索上, 而不用去管之前的结果.
materialize 操作符: 将序列中的事件包裹起来, 原样呈现给订阅者, 而非事件中包含的元素, 这样就可以提前对子序列中的事件进行处理.
它非常适用于对子序列没有直接控制的情况.(比如网络请求操作…)
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 () { 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) }) exampleOf(msg: "map 操作符" , action: { bag in Observable .of(1 , 2 , 3 , 4 , 5 ) .map({ "元素 \($0 * 2 ) " }) .subscribe(onNext: { print ($0 ) }).disposed(by: bag) }) 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 ) }) 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 ) }) 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({ $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 ) }) 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({ guard $0 .error == nil else { print ($0 .error.debugDescription) return false } return true }) .dematerialize() .subscribe(onNext: { 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 ) }) }