RxSwift(五)操作符的使用

在RxSwift中,有許多實用的操作符洒沦,也可以稱之為高階函數(shù)豹绪,可以幫助我們創(chuàng)建特定功能的序列,或者組合變換原有的序列申眼,生成一個新的序列瞒津。這里記錄一下,可以作為手冊以供快速查看括尸。

組合操作符

  • merge
    將多個序列合并成一個新序列仲智,當這多個序列中某一個序列發(fā)出一個元素時,新序列就將這個元素發(fā)出姻氨,當某一個序列發(fā)出error時钓辆,新序列也發(fā)出error,并終止序列。
        let subject1 = PublishSubject<String>()
        let subject2 = PublishSubject<String>()
        Observable.of(subject1, subject2)
            .merge()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        subject1.onNext("R")
        subject1.onNext("x")
        subject2.onNext("S")
        subject2.onNext("w")
        subject1.onNext("i")
        subject2.onNext("f")
        subject1.onNext("t")

打忧傲:

R
x
S
w
i
f
t
  • zip
    將多個(最多不超過8個) 序列的元素組合壓縮功戚,而且是等到每個序列元素事件一一對應地湊齊之后再合并,然后將合并的結果元素發(fā)出來似嗤。組合時啸臀,嚴格按照序列的索引數(shù)進行組合。即返回序列第一個元素烁落,是由每一個源序列的第一個元素組合出來乘粒,它的第二個元素 ,是由每一個源序列的第二個元素組合出來的伤塌,以此類推灯萍。它的元素數(shù)量等于源序列中元素數(shù)量最少的那個序列。
        let stringSubject = PublishSubject<String>()
        let intSubject = PublishSubject<Int>()

        Observable.zip(stringSubject, intSubject) { stringElement, intElement in
                "\(stringElement) \(intElement)"
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        stringSubject.onNext("R")
        stringSubject.onNext("x")   // 到這里存儲了 R X, 但是不會響應
        intSubject.onNext(1)    // 與R 組合成一個新序列每聪,元素:R 1
        intSubject.onNext(2)    // 與X 組合成一個新序列旦棉,元素:X 2
        stringSubject.onNext("Swift")   // 保存Swift
        intSubject.onNext(3)   // 與Swift 組合成一個新序列,元素:Swift 3
        // 劃重點: 只有兩個序列同時有值的時候才會響應药薯,否則存值

打影舐濉:

R 1
x 2
Swift 3
  • combineLatest
    將多個序列中最新的元素組合起來,然后將這個組合的結果發(fā)出來童本。這些源序列中任何一個發(fā)出一個元素真屯,他都會發(fā)出一個元素(前提是,這些序列曾經(jīng)發(fā)出過元素)穷娱。應用:同時滿足條件下觸發(fā)業(yè)務绑蔫,如登錄賬號、密碼合法性校驗鄙煤。
        let stringSub = PublishSubject<String>()
        let intSub = PublishSubject<Int>()
        Observable.combineLatest(stringSub, intSub) { strElement, intElement in
                "\(strElement) \(intElement)"
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        stringSub.onNext("R")   // 保存R
        stringSub.onNext("x")   // 保存x覆蓋了R,和zip不一樣
        intSub.onNext(1)        // 這時兩個序列都有元素茶袒,響應 x 1
        intSub.onNext(2)        // 保存1覆蓋了2梯刚,都有值, 響應 x 2
        stringSub.onNext("Swift") // 保存Swift覆蓋了x薪寓, 都有值亡资,響應 Swift 2

打咏冶薄:

x 1
x 2
Swift 2
  • switchLatest
    將序列發(fā)出的元素轉換成一個新序列构拳,并從新序列發(fā)出元素煌茬。
        let switchLatestSub1 = BehaviorSubject(value: "R")
        let switchLatestSub2 = BehaviorSubject(value: "1")
        // 選擇了 switchLatestSub1 就不會監(jiān)聽 switchLatestSub2
        let switchLatestSub  = BehaviorSubject(value: switchLatestSub1)  
        
        switchLatestSub.asObservable()
            .switchLatest()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        switchLatestSub1.onNext("x")
        switchLatestSub1.onNext("_")
        switchLatestSub2.onNext("2")
        switchLatestSub2.onNext("3")  // 2-3都會不會監(jiān)聽恕沫,保存的元素由2覆蓋1测萎,3覆蓋2
        switchLatestSub.onNext(switchLatestSub2)   // 切換到 switchLatestSub2
        switchLatestSub1.onNext("*")
        switchLatestSub1.onNext("Swift") // 原理同上埂蕊,最后保存的元素為Swift
        switchLatestSub2.onNext("4")
        switchLatestSub.onNext(switchLatestSub1) // 切換到 switchLatestSub1

打痈谢臁:

R
x
_
3
4
Swift
  • concat
    將多個序列按順序串聯(lián)起來植锉,只有當上一個序列發(fā)出了completed事件,才會開始發(fā)送下一個序列事件幸斥。
        let concatSub1 = BehaviorSubject(value: "1")
        let concatSub2 = BehaviorSubject(value: "A")
        let concatSub = BehaviorSubject(value: concatSub1)
        
        concatSub.asObservable()
            .concat()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        concatSub1.onNext("2")
        concatSub.onNext(concatSub2)    // 切換到 concatSub2
        concatSub2.onNext("B")
        concatSub2.onNext("C")    // B-C都不會監(jiān)聽,但是默認保存由 B覆蓋A C覆蓋B
        concatSub1.onCompleted()    // 結束concatSub1
        concatSub2.onNext("D")

打悠ヒ :

1
2
C
D
  • startWith
    在發(fā)出序列的事件元素之前,會先發(fā)出這些預先插入的事件元素甲葬。
        Observable.of("1", "2", "3", "4")
            .startWith("A")
            .startWith("B")
            .startWith("C", "a", "b")
            .subscribe(onNext: { print($0) })
            .disposed(by: DisposeBag())

打永炔:

C
a
b
B
A
1
2
3
4
  • withLatestFrom
    將兩個序列最新的元素組合起來,當?shù)谝粋€序列發(fā)出一個元素经窖,就將組合后的元素發(fā)送出來坡垫。
        let withLatestFromStrSub = PublishSubject<String>()
        let withLatestFromIntSub = PublishSubject<Int>()
        // 當withLatestFromStrSub發(fā)出一個元素時,
        // 就立即取出withLatestFromIntSub最新的元素画侣,
        // 將withLatestFromStrSub 中最新的元素strElement和withLatestFromIntSub最新的元素intElement組合冰悠,
        //然后把組合結果 strElement+intElement發(fā)送出去
        withLatestFromStrSub.withLatestFrom(withLatestFromIntSub) { strElement, intElement in
            "\(strElement) \(intElement)"
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        // withLatestFromStrSub發(fā)出一個元素時,
        // 立即取出withLatestFromIntSub最新的元素棉钧,
        // 然后把withLatestFromIntSub中最新的元素發(fā)送出去
//        withLatestFromStrSub.withLatestFrom(withLatestFromIntSub)
//            .subscribe(onNext: { print($0) })
//            .disposed(by: disposeBag)
        withLatestFromStrSub.onNext("R")
        withLatestFromStrSub.onNext("x") // 存了x覆蓋R
        withLatestFromIntSub.onNext(1)
        withLatestFromIntSub.onNext(2)      // 存了2覆蓋1
        withLatestFromStrSub.onNext("Swift") // 存了Swift覆蓋x屿脐,withLatestFromIntSub有最新元素2,發(fā)出組合序列事件
        withLatestFromStrSub.onNext("Hello") // 存了Hello覆蓋Swift宪卿,withLatestFromIntSub有最新元素2的诵,發(fā)出組合序列事件

打印:

Swift 2
Hello 2
2
2

轉換操作符

  • map
    通過傳入一個閉包把原序列轉變?yōu)橐粋€新序列佑钾,map函數(shù)會將原序列的所有元素進行轉換西疤。
        let ob = Observable.of(1,2,3,4)
        ob.map { (number) -> Int in
            return number+2
            }
            .subscribe{
                print("\($0)")
            }
            .disposed(by: disposeBag)

打印:

next(3)
next(4)
next(5)
next(6)
completed
  • flatMap
    升維:flatMap 操作符會對源序列的每一個元素應用一個轉換方法休溶,將他們轉換成 Observables代赁,降維:然后將這些 Observables 的元素合并成一個序列之后再發(fā)送出來。
        let strSub = BehaviorSubject(value: "A")
        let intSub = BehaviorSubject(value: "1")
        let flatSub = BehaviorSubject(value: strSub)
        
        flatSub.asObservable()
            .flatMap { $0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        strSub.onNext("B")
        flatSub.onNext(intSub)  // 加入intSub序列兽掰,發(fā)出intSub和strSub序列元素轉化后的序列
        intSub.onNext("2")
        strSub.onNext("C")
        intSub.onNext("3")

打影虐:

A
B
1
2
C
3
  • flatMapLatest
    將序列元素轉換成 Observables,然后取這些 Observables 中最新的一個發(fā)送孽尽。若轉換出一個新的 Observables窖壕,就只發(fā)出它的元素,舊的 Observables 的元素將被忽略掉杉女。
        let strSub = BehaviorSubject(value: "A")
        let intSub = BehaviorSubject(value: "1")
        let flatSub = BehaviorSubject(value: strSub)
        
        flatSub.asObservable()
            .flatMapLatest { $0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        strSub.onNext("B")
        // 加入intSub序列瞻讽,發(fā)出intSub元素轉化后的序列,忽略strSub的轉化序列
        flatSub.onNext(intSub)  
        intSub.onNext("2")
        strSub.onNext("C")
        intSub.onNext("3")

打友妗:

A
B
1
2
3

flatMapLatest實際上是mapswitchLatest操作符的組合速勇。
相對的有flatMapFirstflatMapFirst只會接收最初加入序列的元素事件坎拐。

  • concatMap
    將源序列的每一個元素轉換烦磁,轉化成一個 Observables养匈。然后將這些Observables 按順序發(fā)出元素。與flatMap 的區(qū)別是:當前一個序列的元素發(fā)送完畢后个初,下一個 Observable 才可以開始發(fā)出元素乖寒。
        let concatMapSubject1 = BehaviorSubject(value: "A")
        let concatMapSubject2 = BehaviorSubject(value: "1")
        let concatMapSubject = BehaviorSubject(value: concatMapSubject1)
        
        concatMapSubject.asObservable()
            .concatMap() { $0 }
            .subscribe { print($0) }
            .disposed(by: disposeBag)
        
        concatMapSubject1.onNext("B")
        concatMapSubject1.onNext("C")
        concatMapSubject.onNext(concatMapSubject2)
        concatMapSubject2.onNext("2")
        concatMapSubject2.onNext("3")   // 保存3覆蓋2
        // concatMapSubject1結束,開始訂閱concatMapSubject2的元素
        concatMapSubject1.onCompleted() 
        concatMapSubject2.onNext("4")

打釉耗纭:

next(A)
next(B)
next(C)
next(3)
next(4)
  • scan
    對第一個元素和傳入的初始參數(shù)使用傳入的閉包運算楣嘁,將結果作為第一個元素發(fā)出。然后珍逸,將結果作為參數(shù)填入到第二個元素的閉包運算中逐虚,創(chuàng)建第二個元素。以此類推谆膳,直到遍歷完全部的元素叭爱。也就是scan 先給一個初始化的參數(shù)數(shù),然后不斷的拿前一個結果和最新的元素進行運算漱病。
        Observable.of(10, 100, 1000)
            .scan(2) { aggregateValue, newValue in
                aggregateValue + newValue // 10 + 2, 100 + 12, 1000 + 112
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打勇蛭怼:

12
112
1112
  • reduce
    將對第一個元素使用傳入的閉包運算。然后杨帽,將結果作為參數(shù)填入到第二個元素的閉包運算中漓穿。以此類推,直到遍歷完全部的元素后發(fā)出最終結果注盈。
        Observable.of(10, 100, 1000)
            .reduce(2) { aggregateValue, newValue in
                aggregateValue + newValue // 1000 + 100 + 10 + 2
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打踊挝!:

1112
  • toArray
    將一個序列轉成一個數(shù)組,并作為一個單一的事件發(fā)送老客,然后結束僚饭。
        Observable.of(1, 2, 3)
            .toArray()
            .subscribe({ print($0) })
            .disposed(by: disposeBag)

打印:

success([1, 2, 3])

過濾操作符

  • filter
    用來過濾掉不符合條件的事件胧砰,僅僅發(fā)出序列中通過判定的元素鳍鸵。
        Observable.of(1,2,3,4,5,6,7,8,9,0)
            .filter { $0 % 2 == 0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打印:

2
4
6
8
0
  • single
    只發(fā)出可觀察序列發(fā)出的第一個元素(或滿足條件的第一個元素)尉间。如果可觀察序列發(fā)出多個元素偿乖,將拋出一個錯誤。
        Observable.of("Rx", "Swift")
            .single()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打游诙省:

Rx
Unhandled error happened: Sequence contains more than one element.
 subscription called from:
        Observable.of("Rx", "Swift")
            .single { $0 == "Swift" }
            .subscribe { print($0) }
            .disposed(by: disposeBag)

打有谙搿:

next(Swift)
completed
  • take
    只發(fā)出頭n個元素外邓,忽略掉后面的元素撤蚊,直接結束序列。
        print("*****take*****")
        Observable.of("A", "B","C", "D")
            .take(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打铀鸹啊:

A
B
  • takeLast
    僅發(fā)送序列的后n個元素侦啸,忽略前面的元素槽唾。
        Observable.of("R", "x","S", "wift")
            .takeLast(3)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打印:

x
S
wift
  • takeWhile
    依次判斷序列的每一個值是否滿足給定的條件光涂, 當?shù)谝粋€不滿足條件的值出現(xiàn)時庞萍,序列便自動結束。
        Observable.of(1, 2, 3, 4, 2, 6)
            .takeWhile { $0 < 3 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打油拧:

1
2
  • takeUntil
    監(jiān)聽源Observable钝计,同時監(jiān)聽一個條件序列。若條件序列發(fā)出一個元素或者產生一個終止事件齐佳,那么源Observable 將自動完成私恬,停止發(fā)送事件。
        let sourceSequence = PublishSubject<String>()
        let referenceSequence = PublishSubject<String>()
        
        sourceSequence
            .takeUntil(referenceSequence)
            .subscribe { print($0) }
            .disposed(by: disposeBag)
        
        sourceSequence.onNext("A")
        sourceSequence.onNext("B")
        sourceSequence.onNext("C")

        referenceSequence.onNext("0") // 條件序列訂閱發(fā)出炼吴,源序列就結束
        
        sourceSequence.onNext("1")
        sourceSequence.onNext("2")
        sourceSequence.onNext("3")

打颖久:

next(A)
next(B)
next(C)
completed
  • skip
    用于跳過序列發(fā)出的前n 個元素事件。
        Observable.of(1, 2, 3, 4, 5, 6)
            .skip(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打庸璞摹:

3
4
5
6
  • skipWhile
    忽略源序列中頭幾個滿足條件的事件荣德。
        Observable.of(1, 7, 3, 4, 5, 6)
            .skipWhile { $0 < 4 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打印:

7
3
4
5
6
  • skipUntil
    與takeUntil類似童芹,監(jiān)聽源Observable涮瞻,同時監(jiān)聽一個條件序列。跳過Observable 中頭幾個元素辐脖,直到條件序列發(fā)出一個元素饲宛。
        let sourceSeq = PublishSubject<String>()
        let referenceSeq = PublishSubject<String>()
        
        sourceSeq.skipUntil(referenceSeq)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
        // 沒有條件序列事件,源序列無法訂閱
        sourceSeq.onNext("A")
        sourceSeq.onNext("B")
        sourceSeq.onNext("C")
        
        referenceSeq.onNext("0") // 訂閱條件序列嗜价,源序列就開始訂閱
        
        sourceSeq.onNext("1")
        sourceSeq.onNext("2")
        sourceSeq.onNext("3")

打油Э佟:

1
2
3
  • elementAt
    只發(fā)出出來中的第 n 個元素,即是只處理指定位置的元素事件久锥。
        Observable.of("R", "X", "S", "wift")
            .elementAt(3)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打蛹矣佟:

wift
  • distinctUntilChanged
    用于過濾掉連續(xù)重復的事件。如果后一個元素和前一個元素是相同的瑟由,那么這個元素將不會被發(fā)出來絮重。不連續(xù)的相同元素不受影響。
        Observable.of("1", "2", "2", "2", "3", "3", "4")
            .distinctUntilChanged()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打哟蹩唷:

1
2
3
4
  • amb
    amb操作符在多個源 Observables中青伤, 取第一個發(fā)出元素或產生事件的 Observable,這個事件可以是一個 next殴瘦,error 或者 completed事件狠角,然后就只發(fā)出這個Observable的元素事件,忽略掉其他的Observables蚪腋。
        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(2)  // 先發(fā)出事件丰歌,之后就只發(fā)出subject2的事件
        subject1.onNext(1)
        subject2.onNext(2)
        subject1.onNext(1)
        subject3.onNext(3)
        subject2.onNext(2)
        subject1.onNext(1)
        subject3.onNext(3)
        subject3.onNext(3)

打右腆:

2
2
2

Debug 操作符

  • debug
    打印所有的訂閱,事件以及銷毀信息立帖。
    打開RxSwift的Debug Mode方式:在 podfile 的末端添加如下代碼眼溶,重新 pod install 一下。
post_install do |installer|
  installer.pods_project.targets.each do |target|
    if target.name == 'RxSwift'
      target.build_configurations.each do |config|
        if config.name == 'Debug'
          config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['-D', 'TRACE_RESOURCES']
        end
      end
    end
  end
end
        var count = 1
        let error = NSError.init(domain: "com.xxx", code: 10000, userInfo: nil)
        let sequenceThatErrors = Observable<String>.create { observer in
            observer.onNext("A")
            observer.onNext("B")
            observer.onNext("C")
            
            if count < 3 {
                observer.onError(error)
                print("onError")
                count += 1
            }
            
            observer.onNext("D")
            observer.onNext("E")
            observer.onNext("F")
            observer.onCompleted()
            
            return Disposables.create()
        }
        
        sequenceThatErrors
            .debug()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打酉隆:

2019-08-27 17:44:45.792: ViewController.swift:572 (testDebug()) -> subscribed
2019-08-27 17:44:45.840: ViewController.swift:572 (testDebug()) -> Event next(A)
A
2019-08-27 17:44:45.840: ViewController.swift:572 (testDebug()) -> Event next(B)
B
2019-08-27 17:44:45.840: ViewController.swift:572 (testDebug()) -> Event next(C)
C
2019-08-27 17:44:45.842: ViewController.swift:572 (testDebug()) -> Event error(Error Domain=com.xxx Code=10000 "(null)")
Unhandled error happened: Error Domain=com.xxx Code=10000 "(null)"
 subscription called from:

2019-08-27 17:44:45.845: ViewController.swift:572 (testDebug()) -> isDisposed
onError
  • RxSwift.Resources.total
    提供所有Rx資源分配的計數(shù)堂飞,在開發(fā)期間檢測泄漏非常有用。
        print(RxSwift.Resources.total)
        let subject = BehaviorSubject(value: "RxSwift")

        let subscription1 = subject.subscribe(onNext: { print($0) })
        print(RxSwift.Resources.total)

        let subscription2 = subject.subscribe(onNext: { print($0) })
        print(RxSwift.Resources.total)

        subscription1.dispose()
        print(RxSwift.Resources.total)

        subscription2.dispose()
        print(RxSwift.Resources.total)

打影笤邸:

4
RxSwift
11
RxSwift
14
12
10

連接操作符

  • publish
    將序列轉換為可被連接的序列酝静。可被連接的序列 在被訂閱后不會發(fā)出元素,直到 connect操作符被應用為止羡玛。這樣你就可以控制序列在什么時候開始發(fā)出元素别智。
        let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).publish()
        
        interval.subscribe(onNext: { print("訂閱: 1, 事件: \($0)") })
            .disposed(by: disposeBag)
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            // 在connect之前的訂閱不會發(fā)出元素,直到connect發(fā)出后
            print("do connect")
            _ = interval.connect()
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            interval.subscribe(onNext: { print("訂閱: 2, 事件: \($0)") })
                .disposed(by: self.disposeBag)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
            interval.subscribe(onNext: { print("訂閱: 3, 事件: \($0)") })
                .disposed(by: self.disposeBag)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
            self.disposeBag = DisposeBag()
        }

打蛹诟濉:

訂閱: 1, 事件: 0
訂閱: 2, 事件: 0
訂閱: 1, 事件: 1
訂閱: 2, 事件: 1
訂閱: 1, 事件: 2
訂閱: 2, 事件: 2
訂閱: 3, 事件: 2
訂閱: 1, 事件: 3
訂閱: 2, 事件: 3
訂閱: 3, 事件: 3
  • replay
    將序列轉換為可被連接的序列薄榛,并且這個可被連接的序列將緩存最新的 n 個元素。當有新的觀察者對它進行訂閱時让歼,它就把這些被緩存的元素發(fā)送給觀察者敞恋。
        
        let sequenceThatErrors = Observable<String>.create { observer in
            observer.onNext("A")
            observer.onNext("B")
            observer.onNext("C")
            observer.onNext("D")
            observer.onNext("E")
            observer.onNext("F")
            return Disposables.create()
        }
        .replay(5)  // 緩存5個元素
        
        sequenceThatErrors
            .subscribe(onNext: {
                print("before connect subscribe \($0)")
            })
            .disposed(by: disposeBag)

        // 在connect之前的訂閱不會發(fā)出元素,直到connect發(fā)出后
        print("do connect")
        _ = sequenceThatErrors.connect()
        
        sequenceThatErrors
            .subscribe(onNext: {
                print("after connect first subscribe \($0)")
            })
            .disposed(by: disposeBag)
        sequenceThatErrors
            .subscribe(onNext: {
                print("after connect second subscribe \($0)")
                })
            .disposed(by: disposeBag)

打幽庇摇:

do connect
before connect subscribe A
before connect subscribe B
before connect subscribe C
before connect subscribe D
before connect subscribe E
before connect subscribe F
after connect first subscribe B
after connect first subscribe C
after connect first subscribe D
after connect first subscribe E
after connect first subscribe F
after connect second subscribe B
after connect second subscribe C
after connect second subscribe D
after connect second subscribe E
after connect second subscribe F
  • multicast
    將序列轉換為可被連接的序列硬猫,同時傳入一個 Subject,每當序列發(fā)送事件時都會觸發(fā)這個 Subject的發(fā)送改执。
        let subject = PublishSubject<Any>()
        subject.subscribe{print("subject:\($0)")}
            .disposed(by: disposeBag)
        
        let netOB = Observable<Any>.create { (observer) -> Disposable in
                sleep(2)// 模擬網(wǎng)絡延遲
                print("開始請求網(wǎng)絡")
                observer.onNext("請求到的網(wǎng)絡數(shù)據(jù)")
                observer.onNext("請求到的本地")
                observer.onCompleted()
                return Disposables.create {
                    print("銷毀")
                }
            }.multicast(subject)
        
        netOB.subscribe(onNext: { (anything) in
                print("訂閱1:",anything)
            })
            .disposed(by: disposeBag)
        
        netOB.subscribe(onNext: { (anything) in
                print("訂閱2:",anything)
            })
            .disposed(by: disposeBag)
        
        _ = netOB.connect()

打有ッ邸:

subject:next(請求到的網(wǎng)絡數(shù)據(jù))
訂閱1: 請求到的網(wǎng)絡數(shù)據(jù)
訂閱2: 請求到的網(wǎng)絡數(shù)據(jù)
subject:next(請求到的本地)
訂閱1: 請求到的本地
訂閱2: 請求到的本地
subject:completed
銷毀

錯誤恢復操作符

  • timeout
    規(guī)定時間內沒有產生元素就產生一個超時的 error事件
        let times = [
            [ "value": 1, "time": 1 ],
            [ "value": 2, "time": 2 ],
            [ "value": 3, "time": 4.1 ]
        ]
        let timeOutOb = Observable.from(times)
            .flatMap({ (anyTime) in
                return Observable.of(anyTime["value"]!)
                    .delaySubscription(Double(anyTime["time"]!), scheduler: MainScheduler.instance)
            })
            .timeout(2, scheduler: MainScheduler.instance)
        timeOutOb.subscribe(onNext: { (value) in
            print("onNext:", value)
        }, onError: { (error) in
            print("error:", error)
        })
        .disposed(by: disposeBag)

打印:

onNext: 1.0
onNext: 2.0
error: Sequence timeout.
  • catchErrorJustReturn
    如果產生錯誤辈挂,返回一個可觀察序列衬横,該序列發(fā)出單個元素,然后終止终蒂。
        let error = NSError.init(domain: "com.xxx", code: 10000, userInfo: nil)
        let sequenceThatFails = PublishSubject<String>()
        
        sequenceThatFails
            .catchErrorJustReturn("AA")
            .subscribe { print($0) }
            .disposed(by: disposeBag)
        
        sequenceThatFails.onNext("BB")
        sequenceThatFails.onNext("CC")  // 正常序列發(fā)送
        sequenceThatFails.onError(error)   // 發(fā)送失敗蜂林,返回設定的錯誤的預案

打印:

next(BB)
next(CC)
next(AA)
completed
  • catchError
    攔截一個 error事件拇泣,將它替換成其他序列噪叙,然后傳遞給觀察者,訂閱新的序列霉翔。
        let recoverySequence = PublishSubject<String>()
        
        sequenceThatFails
            .catchError {
                print("Error:", $0)
                return recoverySequence  // 截獲到了錯誤序列睁蕾,,返回一個新序列
            }
            .subscribe { print($0) }
            .disposed(by: disposeBag)
        
        sequenceThatFails.onNext("AA")
        sequenceThatFails.onNext("BB") // 正常序列發(fā)送成功的
        sequenceThatFails.onError(error) // 發(fā)送失敗的序列
        
        recoverySequence.onNext("CC")   // 替換的序列發(fā)送信號
        sequenceThatFails.onNext("DD")  // 原序列已結束,不能放松信號
        recoverySequence.onNext("EE")
next(AA)
next(BB)
Error: Error Domain=com.xxx Code=10000 "(null)"
next(CC)
next(EE)
  • retry
    如果源序列產生一個錯誤事件早龟,重新對它進行訂閱惫霸,讓它有機會不產生 error 事件。即便源序列產生了一個 error事件葱弟,retry總是對觀察者發(fā)出 next 事件壹店,所以這樣可能會產生重復的元素。
        var count = 1 // 外界變量控制流程
        let sequenceRetryErrors = Observable<String>.create { observer in
            observer.onNext("AA")
            observer.onNext("BB")
            observer.onNext("CC")
            
            if count == 1 { // 流程進來之后就會過度-這里的條件可以作為出口,失敗的次數(shù)
                observer.onError(error)  // 接收到了錯誤序列,重試序列發(fā)生
                print("onError")
                count += 1
            }
            
            observer.onNext("DD")
            observer.onNext("EE")
            observer.onCompleted()
            
            return Disposables.create()
        }
        
        sequenceRetryErrors
            .retry()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)

打又ゼ印:

AA
BB
CC
onError
AA
BB
CC
DD
EE

設置重新訂閱次數(shù)(retry(_:))

        let sequenceThatErrors = Observable<String>.create { observer in
            observer.onNext("AA")
            observer.onNext("BB")
            observer.onNext("CC")
            
            observer.onError(error)
            observer.onNext("DD")
            observer.onNext("EE")
            observer.onCompleted()
            
            return Disposables.create()
        }
        
        sequenceThatErrors
            .retry(3)  // 重新訂閱3次
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
        
    }

打庸杪:

AA
BB
CC
AA
BB
CC
AA
BB
CC
Unhandled error happened: Error Domain=com.xxx Code=10000 "(null)"
 subscription called from:

總結:
篇幅較長,想快速了解請直接看這里藏杖。

  1. 組合操作符

    • merge
      將多個序列合并成一個新序列将塑,當這多個序列中某一個序列發(fā)出一個元素時,新序列就將這個元素發(fā)出蝌麸,當某一個序列發(fā)出error時点寥,新序列也發(fā)出error,并終止序列来吩。
    • zip
      將多個(最多不超過8個) 序列的元素組合壓縮敢辩,而且是等到每個序列元素事件一一對應地湊齊之后再合并,然后將合并的結果元素發(fā)出來弟疆。
    • combineLatest
      將多個序列中最新的元素組合起來戚长,然后將這個組合的結果發(fā)出來。
    • switchLatest
      將序列發(fā)出的元素轉換成一個新序列怠苔,并從新序列發(fā)出元素同廉。
    • concat
      將多個序列按順序串聯(lián)起來,只有當上一個序列發(fā)出了completed事件柑司,才會開始發(fā)送下一個序列事件迫肖。
    • startWith
      在發(fā)出序列的事件元素之前,會先發(fā)出這些預先插入的事件元素攒驰。
    • withLatestFrom
      將兩個序列最新的元素組合起來咒程,當?shù)谝粋€序列發(fā)出一個元素,就將組合后的元素發(fā)送出來讼育。
  2. 轉換操作符

    • map
      通過傳入的閉包把原序列轉變?yōu)橐粋€新序列帐姻,map函數(shù)會將原序列的所有元素進行轉換。
    • flatMap
      升維:對源序列的每一個元素應用轉換方法奶段,將他們轉換成 Observables饥瓷,降維:然后將這些 Observables 的元素合并成一個序列之后再發(fā)送出來。
    • flatMapLatest
      將序列元素轉換成 Observables痹籍,然后取這些 Observables 中最新的一個發(fā)送呢铆。若轉換出一個新的 Observables,就只發(fā)出它的元素蹲缠,舊的 Observables 的元素將被忽略掉棺克。
    • concatMap
      將源序列的每一個元素轉換悠垛,轉化成一個 Observables。然后將這些Observables 按順序發(fā)出元素娜谊。與flatMap 的區(qū)別是:當前一個序列的元素發(fā)送完畢后确买,下一個 Observable 才可以開始發(fā)出元素。
    • scan
      遍歷全部元素纱皆,對第一個元素和傳入的初始參數(shù)使用傳入的閉包運算湾趾,將結果作為第一個元素發(fā)出。然后不斷的拿前一個結果和最新的元素進行運算派草,并發(fā)出結果搀缠。
    • reduce
      將對第一個元素使用傳入的閉包運算。然后近迁,將結果作為參數(shù)填入到第二個元素的閉包運算中艺普。以此類推,直到遍歷完全部的元素后發(fā)出最終結果鉴竭。
    • toArray
      將一個序列轉成一個數(shù)組衷敌,并作為一個單一的事件發(fā)送,然后結束拓瞪。
  3. 過濾操作符

    • filter
      用來過濾掉不符合條件的事件缴罗,僅僅發(fā)出序列中通過判定的元素。
    • single
      只發(fā)出可觀察序列發(fā)出的第一個元素(或滿足條件的第一個元素)祭埂。如果可觀察序列發(fā)出多個元素面氓,將拋出一個錯誤。
    • take
      只發(fā)出頭n個元素蛆橡,忽略掉后面的元素舌界,直接結束序列。
    • takeLast
      僅發(fā)送序列的后n個元素泰演,忽略前面的元素呻拌。
    • takeWhile
      依次判斷序列的每一個值是否滿足給定的條件, 當第一個不滿足條件的值出現(xiàn)時睦焕,序列便自動結束藐握。
    • takeUntil
      監(jiān)聽源Observable,同時監(jiān)聽一個條件序列垃喊。若條件序列發(fā)出一個元素或者產生一個終止事件猾普,那么源Observable 將自動完成,停止發(fā)送事件本谜。
    • skip
      用于跳過序列發(fā)出的前n 個元素事件初家。
    • skipWhile
      忽略源序列中頭幾個滿足條件的事件。
    • skipUntil
      監(jiān)聽源Observable,同時監(jiān)聽一個條件序列溜在。跳過Observable 中頭幾個元素陌知,直到條件序列發(fā)出一個元素。
    • elementAt
      只發(fā)出出來中的第 n 個元素掖肋,即是只處理指定位置的元素事件仆葡。
    • distinctUntilChanged
      用于過濾掉連續(xù)重復的事件。如果后一個元素和前一個元素是相同的培遵,那么這個元素將不會被發(fā)出來。不連續(xù)的相同元素不受影響登刺。
    • amb
      在多個源 Observables中籽腕, 取第一個產生事件的 Observable,忽略掉其他的Observables纸俭。
  4. Debug 操作符

    • debug
      打印所有的訂閱皇耗,事件以及銷毀信息。
    • RxSwift.Resources.total
      提供所有Rx資源分配的計數(shù)揍很,在開發(fā)期間檢測泄漏非常有用
  5. 連接操作符郎楼。

    • publish
      將序列轉換為可被連接的序列可被連接的序列 在被訂閱后不會發(fā)出元素窒悔,直到 connect 操作符被應用為止呜袁。
    • replay
      將序列轉換為可被連接的序列,并且這個可被連接的序列將緩存最新的 n 個元素简珠。當有新的觀察者對它進行訂閱時阶界,它就把這些被緩存的元素發(fā)送給觀察者。
    • multicast
      將序列轉換為可被連接的序列聋庵,同時傳入一個 Subject膘融,每當序列發(fā)送事件時都會觸發(fā)這個 Subject 的發(fā)送。
  6. 錯誤恢復操作符

    • timeout
      規(guī)定時間內沒有產生元素就產生一個超時的 error 事件祭玉。
    • catchErrorJustReturn
      如果產生錯誤氧映,返回一個可觀察序列,該序列發(fā)出單個元素脱货,然后終止岛都。
    • catchError
      攔截 error 事件,將它替換成其他序列振峻,然后傳遞給觀察者疗绣,訂閱新的序列。
    • retry
      如果源序列產生一個錯誤事件铺韧,重新對它進行訂閱多矮,讓它有機會不產生 error 事件。可設置重新訂閱次數(shù)塔逃,默認遇到一次錯誤事件重新訂閱一次讯壶。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市湾盗,隨后出現(xiàn)的幾起案子伏蚊,更是在濱河造成了極大的恐慌,老刑警劉巖格粪,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躏吊,死亡現(xiàn)場離奇詭異,居然都是意外死亡帐萎,警方通過查閱死者的電腦和手機比伏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疆导,“玉大人赁项,你說我怎么就攤上這事〕憾危” “怎么了悠菜?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長败富。 經(jīng)常有香客問我悔醋,道長,這世上最難降的妖魔是什么兽叮? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任篙顺,我火速辦了婚禮,結果婚禮上充择,老公的妹妹穿的比我還像新娘德玫。我一直安慰自己,他們只是感情好椎麦,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布宰僧。 她就那樣靜靜地躺著,像睡著了一般观挎。 火紅的嫁衣襯著肌膚如雪琴儿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天嘁捷,我揣著相機與錄音造成,去河邊找鬼。 笑死雄嚣,一個胖子當著我的面吹牛晒屎,可吹牛的內容都是我干的喘蟆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼鼓鲁,長吁一口氣:“原來是場噩夢啊……” “哼蕴轨!你這毒婦竟也來了?” 一聲冷哼從身側響起骇吭,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤橙弱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后燥狰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棘脐,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年龙致,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛀缝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡净当,死狀恐怖内斯,靈堂內的尸體忽然破棺而出蕴潦,到底是詐尸還是另有隱情像啼,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布潭苞,位于F島的核電站忽冻,受9級特大地震影響,放射性物質發(fā)生泄漏此疹。R本人自食惡果不足惜僧诚,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝗碎。 院中可真熱鬧湖笨,春花似錦、人聲如沸蹦骑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眠菇。三九已至边败,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捎废,已是汗流浹背笑窜。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留登疗,地道東北人排截。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匾寝。 傳聞我的和親對象是個殘疾皇子搬葬,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內容