RxSwift(4)— 高階函數(上

就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!swift


RxSwift 目錄直通車 --- 和諧學習,不急不躁!數組


由於RxSwift,咱們遊刃在函數響應式的世界裏!若是你想玩得更爽,那麼這一篇RxSwift-高階函數對你來講是必需要掌握的內容!只有你玩好了高階函數才能在實際開發中真正地享受:萬物皆Rx網絡

1:組合操做符

1.1:startWith

  • 在開始從可觀察源發出元素以前,發出指定的元素序列
print("*****startWith*****")
Observable.of("1", "2", "3", "4")
    .startWith("A")
    .startWith("B")
    .startWith("C", "a", "b")
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
//效果: CabBA1234
複製代碼

1.2:merge

  • 將源可觀察序列中的元素組合成一個新的可觀察序列,並將像每一個源可觀察序列發出元素同樣發出每一個元素
print("*****merge*****")
let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()
// merge subject1和subject2
Observable.of(subject1, subject2)
    .merge()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

subject1.onNext("C")
subject1.onNext("o")
subject2.onNext("o")
subject2.onNext("o")
subject1.onNext("c")
subject2.onNext("i")
// Cooci - 任何一個響應都會勾起新序列響應
複製代碼

1.3:zip

  • 將多達8個源可觀測序列組合成一個新的可觀測序列,並將從組合的可觀測序列中發射出對應索引處每一個源可觀測序列的元素
print("*****zip*****")
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("C")
stringSubject.onNext("o") // 到這裏存儲了 C o 可是不會響應除非;另外一個響應

intSubject.onNext(1) // 勾出一個
intSubject.onNext(2) // 勾出另外一個
stringSubject.onNext("i") // 存一個
intSubject.onNext(3) // 勾出一個
// 說白了: 只有兩個序列同時有值的時候纔會響應,不然存值
複製代碼

1.4:combineLatest

  • 將8源可觀測序列組合成一個新的觀測序列,並將開始發出聯合觀測序列的每一個源的最新元素可觀測序列一旦全部排放源序列至少有一個元素,而且當源可觀測序列發出的任何一個新元素
print("*****combineLatest*****")
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("L") // 存一個 L
stringSub.onNext("G") // 存了一個覆蓋 - 和zip不同
intSub.onNext(1)      // 發現strOB也有G 響應 G 1
intSub.onNext(2)      // 覆蓋1 -> 2 發現strOB 有值G 響應 G 2
stringSub.onNext("Cooci") // 覆蓋G -> Cooci 發現intOB 有值2 響應 Cooci 2
// combineLatest 比較zip 會覆蓋
// 應用很是頻繁: 好比帳戶和密碼同時知足->才能登錄. 不關係帳戶密碼怎麼變化的只要查看最後有值就能夠 loginEnable
複製代碼

1.5:switchLatest

  • 將可觀察序列發出的元素轉換爲可觀察序列,並從最近的內部可觀察序列發出元素
print("*****switchLatest*****")
let switchLatestSub1 = BehaviorSubject(value: "L")
let switchLatestSub2 = BehaviorSubject(value: "1")
let switchLatestSub  = BehaviorSubject(value: switchLatestSub1)// 選擇了 switchLatestSub1 就不會監聽 switchLatestSub2

switchLatestSub.asObservable()
    .switchLatest()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

switchLatestSub1.onNext("G")
switchLatestSub1.onNext("_")
switchLatestSub2.onNext("2")
switchLatestSub2.onNext("3") // 2-3都會不會監聽,可是默認保存由 2覆蓋1 3覆蓋2
switchLatestSub.onNext(switchLatestSub2) // 切換到 switchLatestSub2
switchLatestSub1.onNext("*")
switchLatestSub1.onNext("Cooci") // 原理同上面 下面若是再次切換到 switchLatestSub1會打印出 Cooci
switchLatestSub2.onNext("4")
複製代碼
  • 上面組合操做符大部分都比較簡單,原理也比較類似,這裏咱們挑出combineLatest底層原理來分析
  • 初始化中self._arity = arity這就是咱們這次管理的序列個數
  • 初始化中self._hasValue就是一個初始化的個數爲arity的,裏面的值都是false,只有爲何這麼初始化後面會講的!
  • 核心邏輯next(_ index: Int)方法中,判斷self._hasValue[index]就是咱們的剛剛初始化的集合,第一次進來就是第一個序列,進來就會標記true,而且_numberOfValues+1,此時就是0->1
  • 繼續往下面走,發現_numberOfValues < arity就會跳過
  • 若是下次仍是第一個序列進來,第一層判斷就通不過,後面仍是跳過
  • 若是下次進來的是第二個序列,那麼第一層判斷就會進去,進來就會標記true,而且_numberOfValues+1,此時就是1->2
  • 第二層判斷也知足條件self._numberOfValues == self._arity,取回let result = try self.getResult()響應結果,而後就發送出去:self.forwardOn(.next(result))
  • 綜合得出combineLatest 必須兩個序列都響應纔會響應最終的結果
  • 固然還有多個序列組合的,原理也是同樣的!你們自行探索

2:映射操做符

2.1:map

  • 轉換閉包應用於可觀察序列發出的元素,並返回轉換後的元素的新可觀察序列。
print("*****map*****")
let ob = Observable.of(1,2,3,4)
ob.map { (number) -> Int in
    return number+2
    }
    .subscribe{
        print("\($0)")
    }
    .disposed(by: disposeBag)
複製代碼

2.2:flatMap and flatMapLatest

  • 將可觀測序列發射的元素轉換爲可觀測序列,並將兩個可觀測序列的發射合併爲一個可觀測序列。
  • 這也頗有用,例如,當你有一個可觀察的序列,它自己發出可觀察的序列,你想可以對任何一個可觀察序列的新發射作出反應(序列中序列:好比網絡序列中還有模型序列)
  • flatMapflatMapLatest的區別是,flatMapLatest只會從最近的內部可觀測序列發射元素
print("*****flatMap*****")
let boy  = LGPlayer(score: 100)
let girl = LGPlayer(score: 90)
let player = BehaviorSubject(value: boy)

player.asObservable()
    .flatMap { $0.score.asObservable() } // 自己score就是序列 模型就是序列中的序列
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
boy.score.onNext(60)
player.onNext(girl)
boy.score.onNext(50)
boy.score.onNext(40)// 若是切換到 flatMapLatest 就不會打印
girl.score.onNext(10)
girl.score.onNext(0)
複製代碼
  • flatMapLatest其實是mapswitchLatest操做符的組合

2.3:scan

  • 從初始就帶有一個默認值開始,而後對可觀察序列發出的每一個元素應用累加器閉包,並以單個元素可觀察序列的形式返回每一箇中間結果
print("*****scan*****")
Observable.of(10, 100, 1000)
    .scan(2) { aggregateValue, newValue in
        aggregateValue + newValue // 10 + 2 , 100 + 10 + 2 , 1000 + 100 + 2
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
// 這裏主要強調序列值之間的關係
複製代碼
  • 映射型高階函數,咱們拿map來進行分析
  • 經過composeMap建立中間序列:Map
  • 初始化中 self._source = source & self._transform = transform 保存源序列和外界傳進去的映射表達式:$0+2
  • MapSink調用on(_ event: Event<SourceType>)來發送信號,發送信號以前let mappedElement = try self._transform(element)取出要發送的結果,就是通過映射表達式處理的結果
  • self.forwardOn(.next(mappedElement))正常發送

3:過濾條件操做符

3.1:filter

  • 僅從知足指定條件的可觀察序列中發出那些元素
print("*****filter*****")
Observable.of(1,2,3,4,5,6,7,8,9,0)
    .filter { $0 % 2 == 0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.2:distinctUntilChanged

  • 抑制可觀察序列發出的順序重複元素
print("*****distinctUntilChanged*****")
Observable.of("1", "2", "2", "2", "3", "3", "4")
    .distinctUntilChanged()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.3:elementAt

  • 僅在可觀察序列發出的全部元素的指定索引處發出元素
print("*****elementAt*****")
Observable.of("C", "o", "o", "c", "i")
    .elementAt(3)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.4:single

  • 只發出可觀察序列發出的第一個元素(或知足條件的第一個元素)。若是可觀察序列發出多個元素,將拋出一個錯誤。
print("*****single*****")
Observable.of("Cooci", "Kody")
    .single()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

Observable.of("Cooci", "Kody")
    .single { $0 == "Kody" }
    .subscribe { print($0) }
    .disposed(by: disposeBag)
複製代碼

3.5:take

  • 只從一個可觀察序列的開始發出指定數量的元素。 上面signal只有一個序列 在實際開發會受到侷限 這裏引出 take 想幾個就幾個
print("*****take*****")
Observable.of("Hank", "Kody","Cooci", "CC")
    .take(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.6:takeLast

  • 僅從可觀察序列的末尾發出指定數量的元素
print("*****takeLast*****")
Observable.of("Hank", "Kody","Cooci", "CC")
    .takeLast(3)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.7:takeWhile

  • 只要指定條件的值爲true,就從可觀察序列的開始發出元素
print("*****takeWhile*****")
Observable.of(1, 2, 3, 4, 5, 6)
    .takeWhile { $0 < 3 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.8:takeUntil

  • 從源可觀察序列發出元素,直到參考可觀察序列發出元素
  • 這個要重點,應用很是頻繁 好比我頁面銷燬了,就不能獲取值了(cell重用運用)
print("*****takeUntil*****")
let sourceSequence = PublishSubject<String>()
let referenceSequence = PublishSubject<String>()

sourceSequence
    .takeUntil(referenceSequence)
    .subscribe { print($0) }
    .disposed(by: disposeBag)

sourceSequence.onNext("Cooci")
sourceSequence.onNext("Kody")
sourceSequence.onNext("CC")

referenceSequence.onNext("Hank") // 條件一出來,下面就走不了

sourceSequence.onNext("Lina")
sourceSequence.onNext("小雁子")
sourceSequence.onNext("婷婷")
複製代碼

3.9:skip

  • 從源可觀察序列發出元素,直到參考可觀察序列發出元素
  • 這個要重點,應用很是頻繁 不用解釋 textfiled 都會有默認序列產生
print("*****skip*****")
Observable.of(1, 2, 3, 4, 5, 6)
    .skip(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

print("*****skipWhile*****")
Observable.of(1, 2, 3, 4, 5, 6)
    .skipWhile { $0 < 4 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

3.10:skipUntil

  • 抑制從源可觀察序列發出元素,直到參考可觀察序列發出元素
print("*****skipUntil*****")
let sourceSeq = PublishSubject<String>()
let referenceSeq = PublishSubject<String>()

sourceSeq
    .skipUntil(referenceSeq)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

// 沒有條件命令 下面走不了
sourceSeq.onNext("Cooci")
sourceSeq.onNext("Kody")
sourceSeq.onNext("CC")

referenceSeq.onNext("Hank") // 條件一出來,下面就能夠走了

sourceSeq.onNext("Lina")
sourceSeq.onNext("小雁子")
sourceSeq.onNext("婷婷")
複製代碼

4:集合控制操做符

4.1:toArray

  • 將一個可觀察序列轉換爲一個數組,將該數組做爲一個新的單元素可觀察序列發出,而後終止
print("*****toArray*****")
Observable.range(start: 1, count: 10)
    .toArray()
    .subscribe { print($0) }
    .disposed(by: disposeBag)
複製代碼

4.2:reduce

  • 從一個設置的初始化值開始,而後對一個可觀察序列發出的全部元素應用累加器閉包,並以單個元素可觀察序列的形式返回聚合結果 - 相似scan
print("*****reduce*****")
Observable.of(10, 100, 1000)
    .reduce(1, accumulator: +) // 1 + 10 + 100 + 1000 = 1111
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
複製代碼

4.3:concat

  • 以順序方式鏈接來自一個可觀察序列的內部可觀察序列的元素,在從下一個序列發出元素以前,等待每一個序列成功終止
print("*****concat*****")
let subject1 = BehaviorSubject(value: "Hank")
let subject2 = BehaviorSubject(value: "1")

let subjectsSubject = BehaviorSubject(value: subject1)

subjectsSubject.asObservable()
    .concat()
    .subscribe { print($0) }
    .disposed(by: disposeBag)

subject1.onNext("Cooci")
subject1.onNext("Kody")

subjectsSubject.onNext(subject2)

subject2.onNext("打印不出來")
subject2.onNext("2")

subject1.onCompleted() // 必需要等subject1 完成了才能訂閱到! 用來控制順序 網絡數據的異步
subject2.onNext("3")
複製代碼

因爲篇幅緣由,這篇博客先寫到這裏,高階函數的用法仍是有點意思的!若是你是一個RxSwift新手,仍是很是建議你們耐着性子好好練習,對你的開發絕對有幫助 請繼續觀看下一篇博客 RxSwift-高階函數(下)閉包

就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!app

相關文章
相關標籤/搜索