美文网首页Swift
RxSwift学习--高阶函数 / 操作符(上)

RxSwift学习--高阶函数 / 操作符(上)

作者: Henry_Jeannie | 来源:发表于2019-08-14 16:39 被阅读0次

    前言

    RxSwift中,高阶函数也可以成为操作符,高阶函数可以帮助我们创建新的序列,或者变化组合原有的序列,从而生成一个新的序列。

    转换操作符

    1. map

    map操作符会通过传入一个函数闭包把原来的 Observable 序列转变为一个新的 Observable 序列,map函数会将源序列的所有元素进行转换,返回一个新序列.


    例子:
        let disposeBag = DisposeBag()
     
        Observable.of(1, 2, 3)
            .map { $0 * 100}
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        //结果:
        100
        200
        300
    

    2. flatMap

    map在做转换的时候容易出现“升维”的情况。即转变之后,从一个序列变成了一个序列的序列。而flatMap 操作符会对源Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。 然后将这些 Observables 的元素合并之后再发送出来。即又将其 降维成一个 Observable 序列。


    这个操作符是非常有用的。比如当 Observable 的元素本身就拥有其他的 Observable 时,我们可以将所有子 Observables 的元素发送出来。

    例子:

        let disposeBag = DisposeBag()
        let Henry = BehaviorSubject(value: 1)
        let Jeannie = BehaviorSubject(value: 2)
        let Henry_Subject = BehaviorSubject(value: Henry)
    
        Henry_Subject.asObservable()
              .flatMap { $0 }
              .subscribe(onNext: { print($0) })
              .disposed(by: disposeBag)
        Henry.onNext(3)
        Henry_Subject.onNext(Jeannie)
        Henry.onNext(5)
        Jeannie.onNext(6)
        
        //结果
        1
        3
        2
        5
        6
    

    3. flatMapLatest

    flatMapLatest操作符会将Observable 的元素转换成其他的 Observable,然后取这些 Observables 中最新的一个。


    flatMapLatest操作符将源Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。一旦转换出一个新的 Observable,就只发出它的元素,旧的 Observables 的元素将被忽略掉。
    • flatMapLatestflatMap 的唯一区别是:flatMapLatest 只会接收最新的 value 事件。
    • flatMapLatest实际上是mapswitchLatest操作符的组合
    • flatMapLatest就会有flatMapFirstflatMapFirstflatMapLatest正好相反:flatMapFirst 只会接收最初的 value 事件。(该操作符可以防止重复请求:
      比如点击一个按钮发送一个请求,当该请求完成前,该按钮点击都不应该继续发送请求。便可该使用 flatMapFirst 操作符。)

    例子:

        let disposeBag = DisposeBag()
        let Henry = BehaviorSubject(value: 1)
        let Jeannie = BehaviorSubject(value: 2)
        let Henry_Subject = BehaviorSubject(value: Henry)
            
        Henry_Subject.asObservable()
            .flatMapLatest{ $0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        Henry.onNext(3)
        Henry_Subject.onNext(Jeannie)
        Jeannie.onNext(5)
        Henry.onNext(6)
        
        
        //结果:
        1
        3
        2
        5
    

    4. concatMap

    concatMap操作符会将 Observable的元素转换成其他的 Observable,然后将这些 Observables串连起来


    concatMap操作符将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。然后让这些Observables 按顺序的发出元素.
    • concatMapflatMap 的唯一区别是:当前一个 Observable 元素发送完毕后,后一个 Observable 才可以开始发出元素。等待前一个Observable 产生完成事件后,才对后一个 Observable 进行订阅。

    例子:

        let disposeBag = DisposeBag()
        let Henry = BehaviorSubject(value: 1)
        let Jeannie = BehaviorSubject(value: 2)
        let Henry_Subject = BehaviorSubject(value: Henry)
            
        Henry_Subject.asObservable()
            .concatMap{ $0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        Henry.onNext(3)
        Henry_Subject.onNext(Jeannie)
        Jeannie.onNext(5)
        Jeannie.onNext(6)
        Henry.onCompleted()
        
        //结果:
        1
        3
        6
    

    5. scan

    scan操作符会持续的将Observable ,然后发出每一次函数返回的结果


    scan 操作符将对第一个元素应用一个函数,将结果作为第一个元素发出。然后,将结果作为参数填入到第二个元素的应用函数中,创建第二个元素。以此类推,直到遍历完全部的元素。也就是scan 先给一个初始化的数,然后不断的拿前一个结果和最新的值进行处理操作。

    例子:

        let disposeBag = DisposeBag()
    
        Observable.of(1, 2, 3, 4, 5)
            .scan(0) { acum, elem in
            acum + elem
        }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
    
        //结果
        1
        3
        6
        10
        15
    

    6. reduce

    reduce操作符和scan操作符还是有点类似的,reduce 操作符将对第一个元素应用一个函数。然后,将结果作为参数填入到第二个元素的应用函数中。以此类推,直到遍历完全部的元素后发出最终结果。


    例子:
        let disposeBag = DisposeBag()
    
        Observable.of(10, 20, 30)
            .reduce(0, accumulator: +)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        //结果:
        60
    

    7.toArray

    toArray操作符先把一个序列转成一个数组,并作为一个单一的事件发送,然后结束。


    例子:
        let disposeBag = DisposeBag()
     
        Observable.of(1, 2, 3)
            .toArray()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        //结果:
        [1,2,3]
    

    组合操作符

    1. merge

    merge操作符会将多个Observables 合并成一个Observable.
    通过使用 merge 操作符可以将多个 Observables 合并成一个,当某一个 Observable 发出一个元素时,它就将这个元素发出。

    image
    如果,其中某一个 Observable 发出一个 onError 事件,那么被合并的 这个Observable 也会将这个onError 事件发出,并且立即终止序列。

    值得注意的是这里被合并的序列元素必须是同类型的。

    例子:

        let disposeBag = DisposeBag()
            
        let Henry = PublishSubject<Int>()
        let Jeannie = PublishSubject<Int>()
            
        Observable.of(Henry, Jeannie)
            .merge()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        Henry.onNext(1)
        Henry.onNext(2)
        Jeannie.onNext(100)
        Henry.onNext(3)
        Henry.onNext(4)
        Jeannie.onNext(1000)
        
        //结果:
        1
        2
        100
        3
        4
        1000
        
    

    2. startWith

    startWith操作符会在 Observable 头部插入一些事件元素。即发出Observable的事件元素之前,会先发出这些预先插入的事件元素。


    如果在Observable头部分多次插入事件元素,那么这些事件元素会一直在Observable头部追加,也就是后插入的先发出来。

    例子:

        let disposeBag = DisposeBag()
            
        Observable.of("1", "2")
            .startWith("A")
            .startWith("B")
            .startWith("a", "b")
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        //结果:
        a
        b
        B
        A
        1
        2
    
    

    3. zip

    zip操作符可将多个 Observables 的元素组合压缩,而且它会等到每个Observable 元素事件一一对应地凑齐之后再合并,然后将每一个组合的结果元素发出来。


    zip操作符最多可以将8个Observables 的元素通过一个函数组合起来,然后将这个组合的结果发出来。它会严格的按照序列的索引数进行组合。例如,返回的 Observable的第一个元素,是由每一个源 Observables 的第一个元素组合出来的。它的第二个元素 ,是由每一个源 Observables 的第二个元素组合出来的。它的第三个元素 ,是由每一个源 Observables 的第三个元素组合出来的,以此类推。它的元素数量等于源 Observables中元素数量最少的那个。

    例子:

        let disposeBag = DisposeBag()
        let Henry = PublishSubject<String>()
        let Jeannie = PublishSubject<String>()
            
        Observable.zip(Henry, Jeannie) { $0 + $1 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        Henry.onNext("1")
        Jeannie.onNext("A")
        Henry.onNext("2")
        Jeannie.onNext("B")
        Jeannie.onNext("C")
        Henry.onNext("3")
        Henry.onNext("4")
        
        //结果:
        1A
        2B
        3C
    

    zip操作符常常用在整合网络请求上。
    比如我们想同时发送两个请求,只有当两个请求都成功后,再将两者的结果整合起来继续往下处理。这个功能就可以通过 zip 来实现。

    4. combineLatest

    combineLatest操作符同样是将多个Observables 序列元素进行合并。但与zip不同的是,每当任意一个 Observable有新的事件发出时,它会将每个Observable 序列的最新的一个事件元素进行合并,然后发送这个组合出来的元素。(前提是,这些 Observables 曾经发出过元素)。

    例子:

        let disposeBag = DisposeBag()
        let Henry = PublishSubject<String>()
        let Jeannie = PublishSubject<String>()
        
        Observable.combineLatest(Henry, Jeannie) { $0 + $1 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        Henry.onNext("1")
        Jeannie.onNext("A")
        Henry.onNext("2")
        Jeannie.onNext("B")
        Jeannie.onNext("C")
        Henry.onNext("3")
        Henry.onNext("4")
        
        //结果:
        1A
        2A
        2B
        2C
        3C
        4C
    

    5. concat

    concat 操作符将多个 Observables 按顺序串联起来,并且只有当前面一个 Observable 序列发出了 completed 事件,才会开始发送下一个 Observable序列事件。


    例子:
        let disposeBag = DisposeBag()
        let Henry = BehaviorSubject(value: 1)
        let Jeannie = BehaviorSubject(value: 2)
        let Henry_Subject = BehaviorSubject(value: Henry)
            
        Henry_Subject.asObservable()
            .concat()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        Henry.onNext(3)
        Henry_Subject.onNext(Jeannie)
        Jeannie.onNext(5)
        Jeannie.onNext(6)
        Henry.onCompleted()
        Jeannie.onNext(7)
        
        //结果:
        1
        3
        6
        7
    

    感觉concat操作符和concatMap操作符比较相似,它们都是要等到前面一个 Observable 序列发出了 completed 事件,才会开始发送下一个 Observable序列事件。

    6. withLatestFrom

    withLatestFrom操作符会将两个 Observables 最新的元素通过一个函数组合起来,当第一个 Observable 发出一个元素,就将组合后的元素发送出来。


    例子:
        let disposeBag = DisposeBag()
        let firstSubject = PublishSubject<String>()
        let secondSubject = PublishSubject<String>()
    
        firstSubject
             .withLatestFrom(secondSubject) {
                  (first, second) in
                  return first + second
             }
             .subscribe(onNext: { print($0) })
             .disposed(by: disposeBag)
    
        firstSubject.onNext("A️")
        secondSubject.onNext("1")
        firstSubject.onNext("B")
        
        //结果:
        B1
    

    过滤条件操作符

    1. filter

    filter操作符就是用来过滤掉某些不符合要求的事件,仅仅发出Observable中通过判定的元素。

    例子:

        let disposeBag = DisposeBag()
    
        Observable.of(11, 22, 3, 8, 2, 1)
              .filter { $0 > 10 }
              .subscribe(onNext: { print($0) })
              .disposed(by: disposeBag)
        
        //结果:
        11
        22
    

    2. take

    take操作符仅仅从 Observable中发出头n 个元素,在满足数量之后会自动发送 .completed事件。

    例子:

        let disposeBag = DisposeBag()
    
        Observable.of(1, 2, 3, 4, 5, 6)
            .take(3)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        //结果:
        1
        2
        3
    

    3. takeLast

    takeLast操作符与take操作符类似,实现仅发送 Observable 序列中的后n个元素,忽略前面的元素。

    例子:

    let disposeBag = DisposeBag()
    
        Observable.of(1, 2, 3, 4, 5, 6)
            .takeLast(3)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        //结果:
        4
        5
        6
    

    4. takeWhile

    takeWhile操作符会依次判断 Observable 序列的每一个值是否满足给定的条件。 当第一个不满足条件的值出现时,它便自动完成。


    例子:
       let disposeBag = DisposeBag()
     
       Observable.of(2, 3, 4, 5, 6)
           .takeWhile { $0 < 4 }
           .subscribe(onNext: { print($0) })
           .disposed(by: disposeBag)
           
        //结果:
        2
        3
    

    5. takeUntil

    takeUntil操作符会忽略掉在第二个Observable 产生事件后发出的那部分元素。也就是,takeUntil 操作符会观测源Observable,它同时观测第二个 Observable。一旦第二个 Observable 发出一个元素或者产生一个终止事件,那么源Observable 将自动完成,停止发送事件。


    例子:
        let disposeBag = DisposeBag()
            
        let Henry = PublishSubject<String>()
        let Jeannie = PublishSubject<String>()
            
        Henry
            .takeUntil(Jeannie)
            .subscribe { print($0) }
            .disposed(by: disposeBag)
            
        Henry.onNext("Good")
        Henry.onNext("Lucky")
        Jeannie.onNext("Bug")
        Henry.onNext("Tnanks")
        Henry.onNext("a lot")
        
        //结果:
        next(Good)
        next(Lucky)
        completed
    

    6. skip

    skip操作符用于跳过源 Observable序列发出的前n 个元素事件。


    例子:
        let disposeBag = DisposeBag()
     
        Observable.of(1, 2, 3, 4)
            .skip(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        //结果:
        3
        4
    

    7. skipWhile

    skipWhile 操作符可以让你忽略源 Observable 中头几个满足条件的事件。

    例子:

        let disposeBag = DisposeBag()
     
        Observable.of(2, 3, 4, 5, 6)
            .skipWhile { $0 < 5 }
            .subscribe(onNext: { print($0) })
             .disposed(by: disposeBag)
       
       //结果:
       5
       6
    

    8. skipUntil

    同上面的 takeUntil类似,skipUntil 除了订阅源 Observable外,通过 skipUntil 方法我们还可以监视另外一个 ObservableskipUntil操作符会跳过Observable 中头几个元素,直到另一个 Observable发出一个元素。


    例子:
        let disposeBag = DisposeBag()
            
        let Henry = PublishSubject<Int>()
        let Jeannie = PublishSubject<Int>()
            
        Henry
            .skipUntil(Jeannie)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        Henry.onNext(1)
        Henry.onNext(2)
        //开始接收消息
        Jeannie.onNext(0)
        Henry.onNext(3)
        Henry.onNext(4)
        //仍然接收消息
        Jeannie.onNext(0)
        Henry.onNext(5)
        
        //结果:
        3
        4
        5
    

    9. elementAt

    elementAt操作符只发出 Observable 中的第 n 个元素,即是只处理指定位置的元素事件


    例子:
        let disposeBag = DisposeBag()
    
        Observable.of(1, 2, 3, 4)
            .elementAt(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
            
        //结果:
        3
    

    10. distinctUntilChanged

    distinctUntilChanged操作符用于过滤掉连续重复的事件。如果后一个元素和前一个元素是相同的,那么这个元素将不会被发出来。如果后一个元素和前一个元素不相同,那么这个元素才会被发出来。

    例子:

        let disposeBag = DisposeBag()
     
        Observable.of(1, 2, 1, 1, 1, 3)
            .distinctUntilChanged()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        //结果
        1
        2
        1
        3
    

    11.amb

    amb操作符在多个源 Observables中, 取第一个发出元素或产生事件的 Observable,这个事件可以是一个 nexterror 或者 completed事件,然后就只发出这个Observable的元素事件,忽略掉其他的Observables


    例子:
        let disposeBag = DisposeBag()
     
        let subject1 = PublishSubject<Int>()
        let subject2 = PublishSubject<Int>()
        let subject3 = PublishSubject<Int>()
     
        subject1
            .amb(subject2)
            .amb(subject3)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
     
        subject2.onNext(1)
        subject1.onNext(20)
        subject2.onNext(2)
        subject1.onNext(40)
        subject3.onNext(0)
        subject2.onNext(3)
        subject1.onNext(60)
        subject3.onNext(0)
        subject3.onNext(0)
        
        //结果:
        1
        2
        3
    

    总结

    关于RxSwift的高阶函数先总结这么一部分。其实通过这些简单的示例来看,这些操作符在我们对序列进行操作的时候会有很大的帮助,而且使用简单。学好RxSwift,走遍天下都不怕。

    感谢RxSwift中文文档

    相关文章

      网友评论

        本文标题:RxSwift学习--高阶函数 / 操作符(上)

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