RxSwift快速指南(二)

作者: ztang | 来源:发表于2016-07-03 14:40 被阅读3954次

    Transform

    接触过FP的应该都知道map,RxSwift也提供对应的方法将Element进行变形,主要的方法有buffer, flatMap, flatMapFirst, flatMapLatest, map, scanwindow, 用的比较多的是mapflatMap

    map

    let disposeBag = DisposeBag()
    Observable.of(1, 2, 3)
        .map { "\($0)\($0)" }
        .subscribeNext { print($0) }
        .addDisposableTo(disposeBag)
    

    根据map的定义:

    public func map<R>(selector: E throws -> R) -> Observable<R> {
        return self.asObservable().composeMap(selector)
    }
    

    selector这个closure负责将E转换为R,而E这里被定义为Observable.of(1, 2, 3)的Int,每个元素会被转换为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

    mapflatMap的区别在于map的selector将用于Observable中的每一个Element,操作完成后,Element的数量和源Observable中的是一样的,而flatMap的selector的调用次数和源Element数量一致,但是由于selector的返回值为一个Observable,所以在操作完成后,得到的Elements为源Element数量*selector返回的Observable的Element数量,然后将所有Element放入一个Observable中,类似于[[1, 2], [2, 3], [3, 4]] -> [1, 2, 2, 3, 3, 4]

    flatMap

    flatMapLatest

    比起mapflatMap,要稍微难理解一点:

    let disposeBag = DisposeBag()
    
    [1, 2, 3].toObservable()
        .flatMapLatest { value  in
            return ["\(value)a", "\(value)b"].toObservable()
        }
        .subscribe { print($0) }
        .addDisposableTo(disposeBag)
    

    根据RxJS flatMapLatest这个代码期望的结果是(RxSwift和Rx系的其他语句具有相似接口,其中RxJava对应的方法是switchMap,在RxJS Source Code也能发现其实它和switchMap是一个函数):

    Next(1a)
    Next(2a)
    Next(3a)
    Next(3b)
    Completed
    

    但是实际上得到的输出结果是:

    Next(1a)
    Next(1b)
    Next(2a)
    Next(2b)
    Next(3a)
    Next(3b)
    Completed
    

    出现这种情况的原因在github的Get Start有解释,问题出现在selector中的toObservable,它的实现使用了Sequence:

    public func toObservable(scheduler: ImmediateSchedulerType? = nil) -> Observable<Generator.Element> {
        return Sequence(elements: self, scheduler: scheduler)
    }
    

    Sequence其实是一个同步队列的实现,在subscribe调用前会生成Next和Completed,因为无论哪种disposable被返回,生成elements的过程都不能被打断。在这种情况下,flatMapLatestflatMap的输出结果一样。

    期望的版本:

    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
    
    flatMapLatest

    flatMap一样,flatMapLatest也会新生成一个Observable的队列,但不同的是它不会合并所有的新Observable中的Element,它会switch到最后一个Observable上(switchMap这个名字感觉更容易让人理解一点),先前建立的Observable将不再被监听,所以代码中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很类似(区别在于scan后的Element数量和源Element数量一致,但是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的第一个参数为上一次操作的返回值,第二个参数为Observable队列中的Element,然后返回处理结果。

    相关文章

      网友评论

      • FongG:请问RXswift的playground跑不起来是什么问题啊
      • Hengry:楼主,请教一个问题,我在做登录的功能时,使用到了flatMapLatest方法,结果我发现一个怪异的现象:断开网络,第一次请求失败,然后点击按钮就不会发送网络请求了?如何解决该问题?

        github链接: https://github.com/ReactiveX/RxSwift/issues/1524

      本文标题:RxSwift快速指南(二)

      本文链接:https://www.haomeiwen.com/subject/yhqcjttx.html