Transform
接觸過FP的應(yīng)該都知道m(xù)ap偎行,RxSwift也提供對應(yīng)的方法將Element進行變形总滩,主要的方法有buffer
, flatMap
, flatMapFirst
, flatMapLatest
, map
, scan
和window
拦盹, 用的比較多的是map
和flatMap
。
map
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
.map { "\($0)\($0)" }
.subscribeNext { print($0) }
.addDisposableTo(disposeBag)
根據(jù)map
的定義:
public func map<R>(selector: E throws -> R) -> Observable<R> {
return self.asObservable().composeMap(selector)
}
selector
這個closure負(fù)責(zé)將E轉(zhuǎn)換為R倒慧,而E這里被定義為Observable.of(1, 2, 3)的Int掖举,每個元素會被轉(zhuǎn)換為String。
flatMap
let disposeBag = DisposeBag()
let sequenceInt = Observable.of(1, 2, 3)
let sequenceString = Observable.of("A", "B", "C", "D")
sequenceInt.flatMap { _ in
return sequenceString
}
.subscribe { print($0) }
.addDisposableTo(disposeBag)
flatMap
的定義:
public func flatMap<O: ObservableConvertibleType>(selector: (E) throws -> O) -> Observable<O.E> {
return FlatMap(source: asObservable(), selector: selector)
}
來看看Rx官方給出的描述:
map | flatMap |
---|---|
Transform the items emitted by an Observable by applying a function to each item | Transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable |
map
和flatMap
的區(qū)別在于map
的selector將用于Observable中的每一個Element首妖,操作完成后偎漫,Element的數(shù)量和源Observable中的是一樣的,而flatMap
的selector的調(diào)用次數(shù)和源Element數(shù)量一致有缆,但是由于selector的返回值為一個Observable象踊,所以在操作完成后,得到的Elements為源Element數(shù)量*selector返回的Observable的Element數(shù)量棚壁,然后將所有Element放入一個Observable中杯矩,類似于[[1, 2], [2, 3], [3, 4]]
-> [1, 2, 2, 3, 3, 4]
。
flatMapLatest
比起map
和flatMap
袖外,要稍微難理解一點:
let disposeBag = DisposeBag()
[1, 2, 3].toObservable()
.flatMapLatest { value in
return ["\(value)a", "\(value)b"].toObservable()
}
.subscribe { print($0) }
.addDisposableTo(disposeBag)
根據(jù)RxJS flatMapLatest這個代碼期望的結(jié)果是(RxSwift和Rx系的其他語句具有相似接口史隆,其中RxJava對應(yīng)的方法是switchMap,在RxJS Source Code也能發(fā)現(xiàn)其實它和switchMap是一個函數(shù)):
Next(1a)
Next(2a)
Next(3a)
Next(3b)
Completed
但是實際上得到的輸出結(jié)果是:
Next(1a)
Next(1b)
Next(2a)
Next(2b)
Next(3a)
Next(3b)
Completed
出現(xiàn)這種情況的原因在github的Get Start有解釋曼验,問題出現(xiàn)在selector中的toObservable
泌射,它的實現(xiàn)使用了Sequence
:
public func toObservable(scheduler: ImmediateSchedulerType? = nil) -> Observable<Generator.Element> {
return Sequence(elements: self, scheduler: scheduler)
}
Sequence
其實是一個同步隊列的實現(xiàn),在subscribe
調(diào)用前會生成Next和Completed鬓照,因為無論哪種disposable被返回熔酷,生成elements的過程都不能被打斷。在這種情況下豺裆,flatMapLatest
和flatMap
的輸出結(jié)果一樣拒秘。
期望的版本:
let disposeBag = DisposeBag()
var charValues: [Variable<Character>] = [Variable("a"), Variable("a"), Variable("a")]
[0, 1, 2].toObservable()
.flatMapLatest { value -> Observable<Character> in
print("Int value: \(value)")
return charValues[value].asObservable()
}
.subscribe { print($0) }
.addDisposableTo(disposeBag)
charValues[2].value = "b"
charValues[0].value = "c" // nothing happen
charValues[1].value = "d" // nothing happen
和flatMap
一樣,flatMapLatest
也會新生成一個Observable的隊列留储,但不同的是它不會合并所有的新Observable中的Element翼抠,它會switch到最后一個Observable上(switchMap
這個名字感覺更容易讓人理解一點),先前建立的Observable將不再被監(jiān)聽获讳,所以代碼中charValues只有最后一個Observable還在被subscribe。
scan
let disposeBag = DisposeBag()
Observable.range(start: 1, count: 3)
.scan(0) { $0 + $1 }
.subscribe { print($0) }
.addDisposableTo(disposeBag)
scan
和swift的原生方法reduce很類似(區(qū)別在于scan后的Element數(shù)量和源Element數(shù)量一致活喊,但是reduce只會返回一個Element)丐膝,在Observable+Single中我們能夠找到它的定義:
public func scan<A>(seed: A, accumulator: (A, E) throws -> A) -> Observable<A> {
return Scan(source: self.asObservable(), seed: seed, accumulator: accumulator)
}
seed
的scan開始的初始值,accumulator
的第一個參數(shù)為上一次操作的返回值,第二個參數(shù)為Observable隊列中的Element帅矗,然后返回處理結(jié)果偎肃。