日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RxSwift之常用高阶函数(操作符Operator)的说明和使用

發布時間:2024/5/21 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RxSwift之常用高阶函数(操作符Operator)的说明和使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、組合操作符

① startWith

  • startWith 方法會在 Observable 序列開始之前插入一些事件元素,即發出事件消息之前,會先發出這些預先插入的事件消息。

  • 如下所示:
Observable.of("2", "3", "4").startWith("1").subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果1234
  • 插入多個數據,如下所示:
Observable.of("2", "3", "4").startWith("1").startWith("0").startWith("B").startWith("A").subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果AB01234

② merge

  • 將將多個(兩個或兩個以上的)Observable 序列合并成一個 Observable 序列,并將像每個源可觀察序列發出元素一樣發出每個元素。

  • 如下所示:
let subject1 = PublishSubject<String>()let subject2 = PublishSubject<String>()Observable.of(subject1, subject2).merge().subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject1.onNext("s")subject1.onNext("w")subject2.onNext("i")subject2.onNext("f")subject1.onNext("t")// 輸出結果swift

③ zip

  • zip 方法可以將多個(兩個或兩個以上的)Observable 序列壓縮成一個 Observable 序列,而且它會等到每個 Observable 事件一一對應地湊齊之后再合并。
  • 可以將多達 8 個源可觀測序列組合成一個新的可觀測序列,并將從組合的可觀測序列中發射出對應索引處每個源可觀測序列的元素。

  • 如下所示:
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("Y")stringSubject.onNext("D")intSubject.onNext(1)intSubject.onNext(2)stringSubject.onNext("W")intSubject.onNext(3)// 輸出結果Y 1D 2W 3
  • 只有兩個序列同時有值的時候才會響應,否則存值。

④ combineLatest

  • combineLatest 是將多個(兩個或兩個以上的)Observable 序列元素進行合并。
    但與 zip 不同的是,每當任意一個 Observable 有新的事件發出時,它會將每個 Observable 序列的最新的一個事件元素進行合并。
  • combineLatest 可以將 8 源可觀測序列組合成一個新的觀測序列,并將開始發出聯合觀測序列的每個源的最新元素可觀測序列,一旦所有排放源序列至少有一個元素,并且當源可觀測序列發出的任何一個新元素。

  • 如下所示:
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("D") // 存一個 DstringSub.onNext("W") // 存了一個覆蓋 - 和zip不一樣intSub.onNext(1) // 發現 strOB 也有 W 響應 W 1intSub.onNext(2) // 覆蓋1 -> 2 發現 strOB 有值W 響應 W 2stringSub.onNext("Y") // 覆蓋W -> Y 發現 intOB 有值2 響應 Y 2// 輸出結果W 1W 2Y 2

⑤ switchLatest

  • 將可觀察序列發出的元素轉換為可觀察序列,并從最近的內部可觀察序列發出元素。
  • switchLatest 方法可以將兩個 Observable 序列合并為一個,每當 self 隊列發射一個元素時,便從第二個序列中取出最新的一個值。
let switchLatestSub1 = BehaviorSubject(value: "Y")let switchLatestSub2 = BehaviorSubject(value: "1")let switchLatestSub = BehaviorSubject(value: switchLatestSub1)// 選擇了 switchLatestSub1 就不會監聽 switchLatestSub2switchLatestSub.asObservable().switchLatest().subscribe(onNext: { print($0) }).disposed(by: disposeBag)switchLatestSub1.onNext("D")switchLatestSub1.onNext("_")switchLatestSub2.onNext("2")switchLatestSub2.onNext("3") // 2-3都會不會監聽,但是默認保存由 2覆蓋1 3覆蓋2switchLatestSub.onNext(switchLatestSub2) // 切換到 switchLatestSub2switchLatestSub1.onNext("*")switchLatestSub1.onNext("W") // 原理同上面 下面如果再次切換到 switchLatestSub1 會打印出 YDWswitchLatestSub2.onNext("4")// 輸出結果YD_34
  • 組合操作符的使用都比較簡單,它們的原理都類似,以 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 必須兩個序列都響應才會響應最終的結果。

⑥ withLatestFrom

  • 將兩個 Observables 最新的元素通過一個函數組合起來,當第一個 Observable 發出一個元素,就將組合后的元素發送出來:

  • withLatestFrom 操作符將兩個 Observables 中最新的元素通過一個函數組合起來,然后將這個組合的結果發出來。當第一個 Observable 發出一個元素時,就立即取出第二個 Observable 中最新的元素,通過一個組合函數將兩個最新的元素合并后發送出去。
  • 當第一個 Observable 發出一個元素時,就立即取出第二個 Observable 中最新的元素,然后把第二個 Observable 中最新的元素發送出去,示例如下:
let disposeBag = DisposeBag() let firstSubject = PublishSubject<String>() let secondSubject = PublishSubject<String>()firstSubject.withLatestFrom(secondSubject).subscribe(onNext: { print($0) }).disposed(by: disposeBag)firstSubject.onNext("🅰?") firstSubject.onNext("🅱?") secondSubject.onNext("1") secondSubject.onNext("2") firstSubject.onNext("🆎")
  • 運行結果:
2
  • 當第一個 Observable 發出一個元素時,就立即取出第二個 Observable 中最新的元素,將第一個 Observable 中最新的元素 first 和第二個 Observable 中最新的元素second組合,然后把組合結果 first+second發送出去,示例如下:
let disposeBag = DisposeBag() let firstSubject = PublishSubject<String>() let secondSubject = PublishSubject<String>()firstSubject.withLatestFrom(secondSubject) {(first, second) inreturn first + second}.subscribe(onNext: { print($0) }).disposed(by: disposeBag)firstSubject.onNext("🅰?") firstSubject.onNext("🅱?") secondSubject.onNext("1") secondSubject.onNext("2") firstSubject.onNext("🆎")
  • 運行結果:
🆎2

二、映射(變換)操作符

① buffer

  • 緩存元素,然后將緩存的元素集合,周期性的發出來:

  • buffer 操作符將緩存 Observable 中發出的新元素,當元素達到某個數量,或者經過了特定的時間,它就會將這個元素集合發送出來。
  • 如下所示,timeSpan 緩存間隔時間、count 緩存個數、scheduler 線程,發送兩個 event 后會觸發訂閱,滿 2 秒也會觸發訂閱,如果 event 沒有發送空數組:
let sub = PublishSubject<String>() sub.buffer(timeSpan: 2, count: 2, scheduler: MainScheduler.asyncInstance).subscribe { event inprint("訂閱1", event)}.disposed(by: disposeBag)sub.onNext("發送1") sub.onNext("發送2")
  • 輸出如下:
訂閱1 next(["發送1", "發送2"]) 訂閱1 next([]) 訂閱1 next([]) 訂閱1 next([])

② map

  • 轉換閉包應用于可觀察序列發出的元素,并返回轉換后的元素的新可觀察序列。

  • 如下所示:
let ob = Observable.of(1,2,3,4)ob.map { (number) -> Int inreturn number+2}.subscribe{print("\($0)")}.disposed(by: disposeBag)// 輸出結果next(3)next(4)next(5)next(6)completed

③ flatMap and flatMapLatest

  • 將可觀測序列發射的元素轉換為可觀測序列,并將兩個可觀測序列的發射合并為一個可觀測序列。
  • 例如,當有一個可觀察的序列,它本身發出可觀察的序列,想能夠對任何一個可觀察序列的新發射做出反應(序列中序列:比如網絡序列中還有模型序列)。
  • flatMap 和 flatMapLatest 的區別是,flatMapLatest 只會從最近的內部可觀測序列發射元素。
  • flatMapLatest 實際上是 map 和 switchLatest 操作符的組合。


  • 如下所示:
let boy = YDWPlayer(score: 100)let girl = YDWPlayer(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)

④ scan

  • 從初始就帶有一個默認值開始,然后對可觀察序列發出的每個元素應用累加器閉包,并以單個元素可觀察序列的形式返回每個中間結果。

  • 如下所示:
Observable.of(10, 100, 1000).scan(2) { aggregateValue, newValue inaggregateValue + 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)來發送信號,發送信號之前 let mappedElement = try self._transform(element) 取出要發送的結果,就是經過映射表達式處理的結果;
    • self.forwardOn(.next(mappedElement)) 正常發送。

⑤ window

  • 將 Observable 分解為多個子 Observable,周期性的將子 Observable 發出來:

  • window 操作符和 buffer 十分相似,buffer 周期性的將緩存的元素集合發送出來,而 window 周期性的將元素集合以 Observable 的形態發送出來。
  • buffer 要等到元素搜集完畢后,才會發出元素序列,而 window 可以實時發出元素序列。
  • 使用示例:
let disposeBag = DisposeBag() let subject = PublishSubject<String>() // 每3個元素作為一個子Observable發出。 subject.window(timeSpan: 1, count: 3, scheduler: MainScheduler.instance).subscribe(onNext: { [weak self] inprint("subscribe: \($0)")$0.asObservable().subscribe(onNext: { print($0) }).disposed(by: self!.disposeBag)}).disposed(by: disposeBag)subject.onNext("a") subject.onNext("b") subject.onNext("c")subject.onNext("1") subject.onNext("2") subject.onNext("3")
  • 運行結果:
subscribe: RxSwift.AddRef<Swift.String> a b c subscribe: RxSwift.AddRef<Swift.String> 1 2 3 subscribe: RxSwift.AddRef<Swift.String>

⑥ concatMap

  • concatMap 將 Observable 的元素轉換成其他的 Observable,然后將這些 Observables 串連起來:

  • concatMap 操作符將源 Observable 的每一個元素應用一個轉換方法,將它們轉換成 Observables,然后讓這些 Observables 按順序的發出元素,當前一個 Observable 元素發送完畢后,后一個 Observable 才可以開始發出元素,等待前一個 Observable 產生完成事件后,才對后一個 Observable 進行訂閱。
  • 如下所示:
let disposeBag = DisposeBag()let subject1 = BehaviorSubject(value: "🍎") let subject2 = BehaviorSubject(value: "🐶")let variable = Variable(subject1)variable.asObservable().concatMap { $0 }.subscribe { print($0) }.disposed(by: disposeBag)subject1.onNext("🍐") subject1.onNext("🍊")variable.value = subject2subject2.onNext("I would be ignored") subject2.onNext("🐱")subject1.onCompleted()subject2.onNext("🐭")
  • 輸出結果:
next(🍎) next(🍐) next(🍊) next(🐱) next(🐭)

⑦ groupBy

  • 將源 Observable 分解為多個子 Observable,并且每個子 Observable 將源 Observable 中“相似”的元素發送出來:

  • groupBy 操作符將源 Observable 分解為多個子 Observable,然后將這些子 Observable 發送出來。它會將元素通過某個鍵進行分組,然后將分組后的元素序列以 Observable 的形態發送出來。
  • 使用示例:
let disposeBag = DisposeBag()// 將奇數偶數分成兩組 Observable<Int>.of(0, 1, 2, 3, 4, 5).groupBy(keySelector: { (element) -> String inreturn element % 2 == 0 ? "偶數" : "基數"}).subscribe { (event) inswitch event {case .next(let group):group.asObservable().subscribe({ (event) inprint("key:\(group.key) event:\(event)")}).disposed(by: disposeBag)default:print("")}} .disposed(by: disposeBag)
  • 運行結果:
key:偶數 event:next(0) key:基數 event:next(1) key:偶數 event:next(2) key:基數 event:next(3) key:偶數 event:next(4) key:基數 event:next(5) key:偶數 event:completed key:基數 event:completed

三、過濾條件操作符

① filter

  • 僅從滿足指定條件的可觀察序列中發出那些元素。

  • 如下所示:
Observable.of(1,2,3,4,5,6,7,8,9,0).filter { $0 % 2 == 0 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果24680

② distinctUntilChanged

  • 抑制可觀察序列發出的順序重復元素:

  • 如下所示:
Observable.of("1", "2", "2", "2", "3", "3", "4").distinctUntilChanged().subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果1234

③ elementAt

  • 僅在可觀察序列發出的所有元素的指定索引處發出元素:

  • 如下所示:
Observable.of("Y", "D", "W", "N", "B").elementAt(3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果N

④ single

  • 只發出可觀察序列發出的第一個元素(或滿足條件的第一個元素)。如果可觀察序列發出多個元素,將拋出一個錯誤。

  • 如下所示:
Observable.of("D", "W").single().subscribe(onNext: { print($0) }).disposed(by: disposeBag)Observable.of("D", "W").single { $0 == "W" }.subscribe { print($0) }.disposed(by: disposeBag)// 輸出結果DUnhandled error happened: Sequence contains more than one element.subscription called from:next(W)completed

⑤ take

  • 只從一個可觀察序列的開始發出指定數量的元素。 signal 只有一個序列,在實際開發會受到局限,這里引出 take 可以不受限制。

  • 如下所示:
Observable.of("A", "B","C", "D").take(2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果AB

⑥ takeLast

  • 僅從可觀察序列的末尾發出指定數量的元素。

  • 如下所示:
Observable.of("A", "B","C", "D").takeLast(3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果BCD

⑦ takeWhile

  • 只要指定條件的值為 true,就從可觀察序列的開始發出元素。

  • 如下所示:
Observable.of(1, 2, 3, 4, 5, 6).takeWhile { $0 < 3 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果12

⑧ takeUntil

  • 從源可觀察序列發出元素,直到參考可觀察序列發出元素。takeUntil 應用非常頻繁 比如頁面銷毀,就不能獲取值(cell 重用運用)。

  • 如下所示:
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("D") // 條件一出來,下面就不執行sourceSequence.onNext("E")sourceSequence.onNext("F")sourceSequence.onNext("G")// 輸出結果next(A)next(B)next(C)completed

⑨ skip

  • 從源可觀察序列發出元素,直到參考可觀察序列發出元素。skip 應用非常頻繁,不用解釋 textfiled 都會有默認序列產生。

  • 如下所示:
Observable.of(1, 2, 3, 4, 5, 6).skip(2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)Observable.of(1, 2, 3, 4, 5, 6).skipWhile { $0 < 4 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果3456456

⑩ skipUntil

  • 抑制從源可觀察序列發出元素,直到參考可觀察序列發出元素。

  • 如下所示:
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("D") // 條件一出來,下面就可以執行sourceSeq.onNext("E")sourceSeq.onNext("F")sourceSeq.onNext("G")// 輸出結果EFG

? ignoreElements

  • 忽略掉所有的元素,只發出 error 或 completed 事件:

  • ignoreElements 操作符將阻止 Observable 發出 next 事件,但是允許他發出 error 或 completed 事件。如果并不關心 Observable 的任何元素,只想知道 Observable 在什么時候終止,那就可以使用 ignoreElements 操作符。
  • 使用示例:
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).ignoreElements().subscribe{print($0)}.disposed(by: disposeBag)
  • 運行結果:
completed

四、集合控制操作符

① toArray

  • 將一個可觀察序列轉換為一個數組,將該數組作為一個新的單元素可觀察序列發出,然后終止。
Observable.range(start: 1, count: 10).toArray().subscribe { print($0) }.disposed(by: disposeBag)// 輸出結果success([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

② reduce

  • 從一個設置的初始化值開始,然后對一個可觀察序列發出的所有元素應用累加器閉包,并以單個元素可觀察序列的形式返回聚合結果 ,類似 scan。

  • 如下所示:
Observable.of(10, 100, 1000).reduce(1, accumulator: +) // 1 + 10 + 100 + 1000 = 1111.subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果1111

③ concat

  • 以順序方式連接來自一個可觀察序列的內部可觀察序列的元素,在從下一個序列發出元素之前,等待每個序列成功終止。

  • 如下所示:
let subject1 = BehaviorSubject(value: "Y")let subject2 = BehaviorSubject(value: "1")let subjectsSubject = BehaviorSubject(value: subject1)subjectsSubject.asObservable().concat().subscribe { print($0) }.disposed(by: disposeBag)subject1.onNext("D")subject1.onNext("W")subjectsSubject.onNext(subject2)subject2.onNext("打印不出來")subject2.onNext("2")subject1.onCompleted() // 必須要等subject1 完成了才能訂閱到,用來控制順序:網絡數據的異步subject2.onNext("3")// 輸出結果next(Y)next(D)next(W)next(2)next(3)

五、從可觀察對象的錯誤通知中恢復的操作符

① catchError

  • 通過切換到提供的恢復可觀察序列,從錯誤事件中恢復:

  • 如下所示:
let dwError = NSError(domain: "com.xx.***", code: 0, userInfo: ["key":"400"]) as? Errorlet sequenceThatFails = PublishSubject<String>()let recoverySequence = PublishSubject<String>()sequenceThatFails.catchError {print("Error:", $0)return recoverySequence // 獲取到了錯誤序列-在中間的閉包操作處理完畢,返回給用戶需要的序列(showAlert)}.subscribe { print($0) }.disposed(by: disposeBag)sequenceThatFails.onNext("Y")sequenceThatFails.onNext("D") // 正常序列發送成功的sequenceThatFails.onError(dwError!) // 發送失敗的序列recoverySequence.onNext("W")// 輸出結果next(Y)next(D)Error: Error Domain=com.xx.*** Code=0 "(null)" UserInfo={key=400}next(W)

② catchErrorJustReturn

  • 從錯誤事件中恢復,方法是返回一個可觀察到的序列,該序列發出單個元素,然后終止。
let sequenceThatFails = PublishSubject<String>()sequenceThatFails.catchErrorJustReturn("A").subscribe { print($0) }.disposed(by: disposeBag)sequenceThatFails.onNext("B")sequenceThatFails.onNext("C") // 正常序列發送成功的// 發送失敗的序列,一旦訂閱到位 返回我們之前設定的錯誤的預案sequenceThatFails.onError(self.dwError) // 輸出結果next(D)next(W)next(Y)completed

③ retry

  • 通過無限地重新訂閱可觀察序列來恢復重復的錯誤事件。

  • 如下所示:
var count = 1 // 外界變量控制流程let sequenceRetryErrors = Observable<String>.create { observer inobserver.onNext("A")observer.onNext("B")observer.onNext("C")if count == 1 {// 流程進來之后就會過度-這里的條件可以作為出口,失敗的次數observer.onError(dwError!) // 接收到了錯誤序列,重試序列發生print("錯誤序列")count += 1}observer.onNext("D")observer.onNext("E")observer.onNext("F")observer.onCompleted()return Disposables.create()}sequenceRetryErrors.retry().subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果ABC錯誤序列ABCDEF

④ retry( _ : ):

  • 通過重新訂閱可觀察到的序列,重復地從錯誤事件中恢復,直到重試次數達到 max 未遂計數。
var count = 1let sequenceThatErrors = Observable<String>.create { observer inobserver.onNext("A")observer.onNext("B")observer.onNext("C")if count < 5 {observer.onError(dwError!)print("錯誤序列")count += 1}observer.onNext("D")observer.onNext("E")observer.onNext("F")observer.onCompleted()return Disposables.create()}sequenceThatErrors.retry(3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果ABC錯誤序列ABC錯誤序列ABC錯誤序列Unhandled error happened: Error Domain=com.xx.*** Code=0 "(null)" UserInfo={key=400}subscription called from:

六、Rx 流程操作符

① debug

  • 打印所有訂閱、事件和處理:
var count = 1let sequenceThatErrors = Observable<String>.create { observer inobserver.onNext("A")observer.onNext("B")observer.onNext("C")if count < 5 {observer.onError(dwError!)print("錯誤序列")count += 1}observer.onNext("D")observer.onNext("E")observer.onNext("F")observer.onCompleted()return Disposables.create()}sequenceThatErrors.retry(3).debug().subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結果ViewController.swift:346 (viewDidLoad()) -> subscribedViewController.swift:346 (viewDidLoad()) -> Event next(A)AViewController.swift:346 (viewDidLoad()) -> Event next(B)BViewController.swift:346 (viewDidLoad()) -> Event next(C)C錯誤序列ViewController.swift:346 (viewDidLoad()) -> Event next(A)AViewController.swift:346 (viewDidLoad()) -> Event next(B)BViewController.swift:346 (viewDidLoad()) -> Event next(C)C錯誤序列ViewController.swift:346 (viewDidLoad()) -> Event next(A)AViewController.swift:346 (viewDidLoad()) -> Event next(B)BViewController.swift:346 (viewDidLoad()) -> Event next(C)C錯誤序列ViewController.swift:346 (viewDidLoad()) -> Event error(Error Domain=com.xx.*** Code=0 "(null)" UserInfo={key=400}) Unhandled error happened: Error Domain=com.xx.*** Code=0 "(null)" UserInfo={key=400}subscription called from:ViewController.swift:346 (viewDidLoad()) -> isDisposed

② RxSwift.Resources.total:

  • 提供所有 Rx 資源分配的計數,這對于在開發期間檢測泄漏非常有用。
print(RxSwift.Resources.total)let subject = BehaviorSubject(value: "A")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)

七、鏈接操作符(Connectable Observable Operators)

① 可連接的序列

  • 可連接的序列(Connectable Observable):
    • 可連接的序列和一般序列不同在于:有訂閱時不會立刻開始發送事件消息,只有當調用 connect() 之后才會開始發送值。
    • 可連接的序列可以讓所有的訂閱者訂閱后,才開始發出事件消息,從而保證想要的所有訂閱者都能接收到事件消息。
  • 普通序列:
// 每隔1秒鐘發送1個事件 let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance)// 第一個訂閱者(立刻開始訂閱) _ = interval.subscribe(onNext: { print("訂閱1: \($0)") })// 第二個訂閱者(延遲5秒開始訂閱) delay(5) {_ = interval.subscribe(onNext: { print("訂閱2: \($0)") }) }
  • 為了方便使用,定義一個延遲執行方法:
/// 延遲執行 /// - Parameters: /// - delay: 延遲時間(秒) /// - closure: 延遲執行的閉包 public func delay(_ delay: Double, closure: @escaping () -> Void) {DispatchQueue.main.asyncAfter(deadline: .now() + delay) {closure()} }
  • 運行結果如下,可以看到第一個訂閱者訂閱后,每隔 1 秒會收到一個值。而第二個訂閱者 5 秒后才收到第一個值 0,所以兩個訂閱者接收到的值是不同步的:
訂閱10 訂閱11 訂閱12 訂閱13 訂閱14 訂閱15 訂閱20 訂閱16 訂閱21

② multicast

  • 將源可觀察序列轉換為可連接序列,并通過指定的主題廣播其發射。
func testMulticastConnectOperators(){let subject = PublishSubject<Any>()subject.subscribe{print("00:\($0)")}.disposed(by: disposeBag)let netOB = Observable<Any>.create { (observer) -> Disposable insleep(2)// 模擬網絡延遲print("開始請求網絡")observer.onNext("請求到的網絡數據")observer.onNext("請求到的本地")observer.onCompleted()return Disposables.create {print("銷毀回調")}}.publish()netOB.subscribe(onNext: { (anything) inprint("訂閱1:",anything)}).disposed(by: disposeBag)netOB.subscribe(onNext: { (anything) inprint("訂閱2:",anything)}).disposed(by: disposeBag)_ = netOB.connect()}
  • 說明:
    • 底層邏輯探索中間變量 ConnectableObservableAdapter 保存了源序列 source、中間序列 makeSubject;
    • 訂閱流程 self.lazySubject.subscribe(observer) 一個懶加載的序列,保證了中間變量 ConnectableObservableAdapter 每一次都是同一個響應序列
      剩下就是 PublishSubject 的訂閱效果;
    • 等待源序列的響應,但是源序列的訂閱是在 connect 函數里面,如果沒有調用 connect 函數,意味著就永遠不會發送響應。這樣背后的邏輯就是,前面所以的發送響應在 connect 函數之前的都沒有任何的意義。
    • 以上也就說明 publish 就是狀態共享的:connnect 一次序列發送一次響應(響應所有訂閱)。

③ replay

  • 將源可觀察序列轉換為可連接的序列,并將向每個新訂閱服務器重放以前排放的緩沖大小;
  • 首先擁有和 publish 一樣的能力,共享 Observable sequence, 其次使用 replay 還需要傳入一個參數(buffer size)來緩存已發送的事件,當有新的訂閱者訂閱了,會把緩存的事件發送給新的訂閱者。

  • 如下所示:
func testReplayConnectOperators() { let interval = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).replay(5)interval.subscribe(onNext: { print(Date.time,"訂閱: 1, 事件: \($0)") }).disposed(by: self.disposeBag)delay(2) { _ = interval.connect() }delay(4) {interval.subscribe(onNext: { print(Date.time,"訂閱: 2, 事件: \($0)") }).disposed(by: self.disposeBag)}delay(8) {interval.subscribe(onNext: { print(Date.time,"訂閱: 3, 事件: \($0)") }).disposed(by: self.disposeBag)}delay(20, closure: {self.disposeBag = DisposeBag()})/**訂閱: 1, 事件: 4訂閱: 1, 事件: 0訂閱: 2, 事件: 0訂閱: 1, 事件: 1訂閱: 2, 事件: 1訂閱: 2, 事件: 4訂閱: 3, 事件: 0訂閱: 3, 事件: 1訂閱: 3, 事件: 2訂閱: 3, 事件: 3訂閱: 3, 事件: 4// 序列從 0開始// 定時器也沒有斷層 sub2 sub3 和 sub1 是同步的*/}

④ publish

  • publish 方法會將一個正常的序列轉換成一個可連接的序列,同時該序列不會立刻發送事件,只有在調用 connect 之后才會開始。

  • 稍微修改“可連接的序列”中的示例:
// 每隔1秒鐘發送1個事件 let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance).publish()// 第一個訂閱者(立刻開始訂閱) _ = interval.subscribe(onNext: { print("訂閱1: \($0)") })// 相當于把事件消息推遲了兩秒 delay(2) {_ = interval.connect() }// 第二個訂閱者(延遲5秒開始訂閱) delay(5) {_ = interval.subscribe(onNext: { print("訂閱2: \($0)") }) }
  • 運行結果:
訂閱10 訂閱11 訂閱12 訂閱22 訂閱13 訂閱23 訂閱14 訂閱24 訂閱15

⑤ refCount

  • 將可被連接的 Observable 轉換為普通 Observable:

  • 可被連接的 Observable 和普通的 Observable 十分相似,不過在被訂閱后不會發出元素,直到 connect 操作符被應用為止。這樣一來可以控制 Observable 在什么時候開始發出元素。
  • refCount 操作符將自動連接和斷開可被連接的 Observable。它將可被連接的 Observable 轉換為普通 Observable。當第一個觀察者對它訂閱時,那么底層的 Observable 將被連接;當最后一個觀察者離開時,那么底層的 Observable 將被斷開連接。
  • 使用示例:
// 每隔1秒鐘發送1個事件 let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance).publish().refCount()// 第一個訂閱者(立刻開始訂閱) _ = interval.subscribe(onNext: { print("訂閱1: \($0)") })// 第二個訂閱者(延遲5秒開始訂閱) delay(5) {_ = interval.subscribe(onNext: { print("訂閱2: \($0)") }) }
  • 運行結果:
訂閱1: 0 訂閱1: 1 訂閱1: 2 訂閱1: 3 訂閱1: 4 訂閱1: 5 訂閱2: 5 訂閱1: 6 訂閱2: 6 訂閱1: 7 訂閱2: 7 訂閱1: 8 訂閱2: 8

⑥ shareReplay

  • 使觀察者共享 Observable,觀察者會立即收到最新的元素,即使這些元素是在訂閱前產生的:

  • shareReplay 操作符將使得觀察者共享源 Observable,并且緩存最新的 n 個元素,將這些元素直接發送給新的觀察者。
  • 使用示例:
// 每隔1秒鐘發送1個事件 let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance).share(replay: 5)// 第一個訂閱者(立刻開始訂閱) _ = interval.subscribe(onNext: { print("訂閱1: \($0)") })// 第二個訂閱者(延遲5秒開始訂閱) delay(5) {_ = interval.subscribe(onNext: { print("訂閱2: \($0)") })} /// 延遲執行 /// - Parameters: /// - delay: 延遲時間(秒) /// - closure: 延遲執行的閉包 public func delay(_ delay: Double, closure: @escaping () -> Void) {DispatchQueue.main.asyncAfter(deadline: .now() + delay) {closure()} }
  • 運行結果:
訂閱1: 0 訂閱1: 1 訂閱1: 2 訂閱1: 3 訂閱1: 4 訂閱2: 0 訂閱2: 1 訂閱2: 2 訂閱2: 3 訂閱2: 4 訂閱1: 5 訂閱2: 5 訂閱1: 6 訂閱2: 6

八、條件和布爾操作符(Conditional and Boolean Operators)

① amb

  • 在多個源 Observables 中,取第一個發出元素或產生事件的 Observable,然后只發出它的元素:

  • 當傳入多個 Observables 到 amb 操作符時,它將取其中一個 Observable:第一個產生事件的那個 Observable,可以是一個 next,error 或者 completed 事件;amb 將忽略掉其它的 Observables。
  • 例如:
let a = Observable<Int>.just(0) let b = Observable<Int>.just(1) let c = Observable<Int>.just(2)Observable<Int>.amb([a, b, c]).subscribe { event inswitch event {case .next(let element):print("element:", element)case .error(let error):print("error:", error)case .completed:print("completed")}}.disposed(by: bag)
  • 因為 a 先執行成功,輸出如下:
輸出: element: 0 completed

② skipWhile

  • 跳過 Observable 中頭幾個元素,直到元素的判定為否:

  • skipWhile 操作符可以讓你忽略源 Observable 中頭幾個元素,直到元素的判定為否后,它才鏡像源 Observable。
  • 使用示例:
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4, 3, 2, 1).skipWhile { $0 < 4 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)
  • 運行結果:
4 3 2 1

九、其它操作符

① connect

  • connect 通知 ConnectableObservable 可以開始發出元素:

  • ConnectableObservable 和普通的 Observable 十分相似,不過在被訂閱后不會發出元素,直到 connect 操作符被應用為止,這樣一來可以等所有觀察者全部訂閱完成后,才發出元素。
  • 如下所示:
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance).publish()_ = intSequence.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })DispatchQueue.main.asyncAfter(deadline: .now() + 2) {_ = intSequence.connect() }DispatchQueue.main.asyncAfter(deadline: .now() + 4) {_ = intSequence.subscribe(onNext: { print("Subscription 2:, Event: \($0)") }) }DispatchQueue.main.asyncAfter(deadline: .now() + 6) {_ = intSequence.subscribe(onNext: { print("Subscription 3:, Event: \($0)") }) }
  • 輸出結果:
Subscription 1:, Event: 0 Subscription 1:, Event: 1 Subscription 2:, Event: 1 Subscription 1:, Event: 2 Subscription 2:, Event: 2 Subscription 1:, Event: 3 Subscription 2:, Event: 3 Subscription 3:, Event: 3 Subscription 1:, Event: 4 Subscription 2:, Event: 4 Subscription 3:, Event: 4 Subscription 1:, Event: 5 Subscription 2:, Event: 5 Subscription 3:, Event: 5 Subscription 1:, Event: 6 Subscription 2:, Event: 6 Subscription 3:, Event: 6 ...

② create

  • 通過一個構建函數完整的創建一個 Observable:

  • create 操作符將創建一個 Observable,需要提供一個構建函數,在構建函數里面描述事件(next,error,completed)的產生過程。
  • 通常情況下一個有限的序列,只會調用一次觀察者的 onCompleted 或者 onError 方法,并且在調用它們后,不會再去調用觀察者的其它方法。
  • 如下所示,創建一個 [0, 1, … 8, 9] 的序列:
let id = Observable<Int>.create { observer inobserver.onNext(0)observer.onNext(1)observer.onNext(2)observer.onNext(3)observer.onNext(4)observer.onNext(5)observer.onNext(6)observer.onNext(7)observer.onNext(8)observer.onNext(9)observer.onCompleted()return Disposables.create() }

③ debounce

  • 過濾掉高頻產生的元素:

  • debounce 操作符將發出這種元素,在 Observable 產生這種元素后,一段時間內沒有新元素產生。
  • 如下所示:
let pb = PublishSubject<Int>() pb.debounce(2, scheduler: MainScheduler.instance).subscribe(onNext: { int inprint("element:", int)}).disposed(by: bag) pb.onNext(1) pb.onNext(2) pb.onNext(3) pb.onNext(4) pb.onNext(5)
  • 指定了兩秒鐘,所以在兩秒鐘以內,只接收了到了最新的 element: 5,因此輸出如下:
element: 5

④ deferred

  • 直到訂閱發生,才創建 Observable,并且為每位訂閱者創建全新的 Observable:

  • deferred 操作符將等待觀察者訂閱它,才創建一個 Observable,它會通過一個構建函數為每一位訂閱者創建新的 Observable。看上去每位訂閱者都是對同一個 Observable 產生訂閱,實際上它們都獲得了獨立的序列。
  • 在一些情況下,直到訂閱時才創建 Observable 是可以保證拿到的數據都是最新的。
  • 如下所示:
let ob = Observable<Int>.deferred { () -> Observable<Int> inlet ob1 = Observable<Int>.create({ ov inov.onNext(1)ov.onNext(2)ov.onCompleted()return Disposables.create()})return ob1 } ob.subscribe(onNext: { int inprint(int) }).disposed(by: bag)
  • 輸出結果:
1 2

⑤ delay

  • 將 Observable 的每一個元素拖延一段時間后發出:

  • delay 操作符將修改一個 Observable,它會將 Observable 的所有元素都拖延一段設定好的時間, 然后才將它們發送出來。
  • 如下所示:
Observable<Int>.just(1).delay(3, scheduler: MainScheduler.instance).subscribe(onNext: { i inprint("element: ", i)}).disposed(by: bag)
  • 延遲 3 秒后輸出:
element: 1

⑥ delaySubscription

  • delaySubscription 操作符將在經過所設定的時間后,才對 Observable 進行訂閱操作。

  • 如下所示:
Observable<Int>.just(2).delaySubscription(3, scheduler: MainScheduler.instance).subscribe(onNext: { i inprint("element: ", i)}).disposed(by: bag)
  • 延遲 3 秒后輸出:
element: 2

⑦ materialize

  • 一個有限的 Observable 將產生零個或者多個 onNext 事件,然后產生一個 onCompleted 或者 onError 事件。materialize 操作符將 Observable 產生的這些事件全部轉換成元素,然后發送出來。

  • 使用示例:
let disposeBag = DisposeBag() Observable.of(1, 2, 1).materialize().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
  • 運行結果:
next(1) next(2) next(1) completed

⑧ dematerialize

  • dematerialize 操作符將 materialize 轉換后的元素還原:

  • 如下所示:
let disposeBag = DisposeBag()Observable.of(1, 2, 1).materialize().dematerialize().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
  • 輸出結果:
1 2 1

⑨ do

  • 當 Observable 的某些事件產生時,可以使用 do 操作符來注冊一些回調操作,這些回調會被單獨調用,它們會和 Observable 原本的回調分離。

  • 如下所示:
let disposeBag = DisposeBag()Observable<[Int]>.of([1, 2, 3]).do(onNext: { element inprint("do element:" ,element)}, onError: { error inprint("do error:", error)}, onCompleted: {print("do completed")}, onSubscribe: {print("do subscribe")}, onSubscribed: {print("do subscribed")}, onDispose: {print("do dispose")}).subscribe { event inswitch event {case .next(let element):print("element:", element)case .error(let error):print("error:", error)case .completed:print("completed")}}.disposed(by: disposeBag)
  • do 優先于 subscribe 打印,因此輸出結果:
do subscribe do subscribed do element: [1, 2, 3] element: [1, 2, 3] do completed completed do dispose

⑩ empty

  • empty 操作符將創建一個 Observable,這個 Observable 只有一個完成事件:

  • 創建一個空 Observable:
let id = Observable<Int>.empty()
  • 它相當于:
let id = Observable<Int>.create { observer inobserver.onCompleted()return Disposables.create() }

? timeout

  • 如果 Observable 在一段時間內沒有產生元素,timeout 操作符將使它發出一個超時的 error 事件。

  • 使用示例:
let disposeBag = DisposeBag() // 定義好每個事件里的值以及發送的時間 let times = [[ "value": 1, "time": 0 ],[ "value": 2, "time": 0.5 ],[ "value": 3, "time": 1.5 ],[ "value": 4, "time": 4 ],[ "value": 5, "time": 5 ]]// 生成對應的 Observable 序列并訂閱 Observable.from(times).flatMap { item inreturn Observable.of(Int(item["value"]!)).delaySubscription(Double(item["time"]!),scheduler: MainScheduler.instance)}.timeout(2, scheduler: MainScheduler.instance) // 超過兩秒沒發出元素,則產生error事件.subscribe(onNext: { element inprint(element)}, onError: { error inprint(error)}).disposed(by: disposeBag)
  • 運行結果:
1 2 3 Sequence timeout

? using

  • 通過使用 using 操作符創建 Observable 時,同時創建一個可被清除的資源,一旦 Observable 終止,那么這個資源就會被清除掉。

  • 使用示例:
// 一個無限序列(每隔0.1秒創建一個序列數) let infiniteInterval$ = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance).do(onNext: { print("infinite$: \($0)") },onSubscribe: { print("開始訂閱 infinite$")},onDispose: { print("銷毀 infinite$")} )// 一個有限序列(每隔0.5秒創建一個序列數,共創建三個 ) let limited$ = Observable<Int>.interval(0.5, scheduler: MainScheduler.instance).take(2).do(onNext: { print("limited$: \($0)") },onSubscribe: { print("開始訂閱 limited$")},onDispose: { print("銷毀 limited$")} )// 使用using操作符創建序列 let o: Observable<Int> = Observable.using({ () -> AnyDisposable inreturn AnyDisposable(infiniteInterval$.subscribe()) }, observableFactory: { _ in return limited$ } ) o.subscribe() class AnyDisposable: Disposable {let _dispose: () -> Voidinit(_ disposable: Disposable) {_dispose = disposable.dispose}func dispose() {_dispose()} }
  • 運行結果:
開始訂閱 infinite$ 開始訂閱 limited$ infinite$: 0 infinite$: 1 infinite$: 2 infinite$: 3 limited$: 0 infinite$: 4 infinite$: 5 infinite$: 6 infinite$: 7 infinite$: 8 limited$: 1 銷毀 limited$ 銷毀 infinite$ 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的RxSwift之常用高阶函数(操作符Operator)的说明和使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

99精品免费久久久久久日本 | 懂色av一区二区三区蜜臀 | 国产精品永久免费观看 | 国产精品99久久久 | 精品一区二区精品 | 韩国一区二区三区视频 | 国内精品久久影院 | 久久看片| 一区二区视频免费在线观看 | 亚洲最大av网站 | 在线观看免费成人av | 天天色天天射综合网 | 99资源网 | 午夜精品一区二区三区在线播放 | 69精品 | 亚洲视频www| 日韩在线免费视频观看 | 免费看成人av | 久久久视频在线 | 五月婷婷综合在线观看 | 香蕉网在线观看 | 成人黄色在线 | 免费观看一区二区 | www.少妇| 91av久久| 成人午夜影视 | 亚洲 在线| 97国产精品免费 | 91在线视频免费观看 | 亚州欧美精品 | 成人免费在线观看av | 五月天av在线 | 99精品99| 在线91色 | 国产精品mv | 亚洲午夜剧场 | 九九免费在线看完整版 | 免费看一级特黄a大片 | 国产麻豆视频免费观看 | 久草www| 一区二区三区电影在线播 | 欧美另类一二三四区 | 欧美性生活一级片 | 久久久久久久久久网站 | 99久久久久久久 | av一区二区三区在线观看 | 4438全国亚洲精品观看视频 | 亚洲综合成人在线 | 成人在线免费观看网站 | 成年人视频在线观看免费 | 欧美在线视频一区二区三区 | 99婷婷 | 九九免费在线观看视频 | 在线观看视频一区二区三区 | 国产精品69av | 九九九九九国产 | 99热99re6国产在线播放 | 国产剧情久久 | 久久久人人人 | 六月丁香在线观看 | 99性视频 | 亚洲视频高清 | 国产综合91| 最近中文字幕免费av | 99精品色 | 欧美性一级观看 | 偷拍福利视频一区二区三区 | 欧美一级电影在线观看 | 中文成人字幕 | 日韩免费在线观看网站 | 中文字幕丝袜制服 | 日本韩国精品一区二区在线观看 | 国产伦精品一区二区三区无广告 | 亚洲精品在线视频网站 | 久久视频在线观看中文字幕 | 天天插天天射 | 久久精品91久久久久久再现 | 五月婷婷中文网 | 99精品国产高清在线观看 | 欧美性爽爽 | 涩av在线| 综合网在线视频 | 九九精品毛片 | 中文字幕欧美日韩va免费视频 | 国产一级黄色免费看 | 不卡电影免费在线播放一区 | 黄色一二级片 | 色之综合网 | 欧美日韩国产一区二区三区在线观看 | 日韩艹| 在线观看免费成人 | 成人国产精品久久久春色 | 国产成人精品亚洲 | av一级在线 | 三级a毛片 | av网址在线播放 | 久久免费的精品国产v∧ | 国产精品一区二 | 欧美男同网站 | 99热都是精品 | 中文字幕麻豆 | 久草免费新视频 | 91视频午夜 | 2000xxx影视 | 亚洲一区动漫 | 中文字幕在线日 | 国产精品久久久久永久免费看 | 91精品视频在线观看免费 | 免费中文字幕在线观看 | 精品国产一区二区三区四 | 在线观看黄色的网站 | 天天射射天天 | www.av在线播放 | 日韩一区二区久久 | 夜夜夜精品| 日日夜夜人人天天 | 精品高清视频 | 日本在线视频网址 | 夜夜骑天天操 | 在线免费中文字幕 | 色是在线视频 | 午夜久久福利视频 | 国产一级精品视频 | 国产高清av免费在线观看 | 亚洲国产电影在线观看 | 在线播放国产一区二区三区 | 97超碰人人干 | 欧美激情第十页 | 国产精品h在线观看 | 久久国产成人午夜av影院潦草 | 欧美日韩亚洲在线观看 | 日韩av美女 | 亚洲国产精品久久久久 | 天天玩天天操天天射 | 奇米影视777四色米奇影院 | 亚洲片在线观看 | 干干日日 | 国产午夜精品一区二区三区四区 | 国内精品美女在线观看 | 99久久国产免费免费 | 亚洲午夜久久久久久久久久久 | 中文字字幕在线 | 国产超碰在线 | 久久免费a | 香蕉免费在线 | 亚洲成人第一区 | 日韩二区在线观看 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 成人免费在线电影 | 国产成人精品免高潮在线观看 | 国产一区二区三区四区大秀 | 高清视频一区二区三区 | 欧美综合在线视频 | 三级黄色理论片 | 久久超碰在线 | 精品国产伦一区二区三区 | 国内精品国产三级国产aⅴ久 | 亚洲精品www久久久久久 | 手机av看片 | 国产黄色大片免费看 | 亚洲午夜久久久综合37日本 | 久久久综合精品 | 香蕉久草 | 丁香av在线 | 91色亚洲 | 亚州av成人 | 久久五月激情 | 国产精品久久久久久一二三四五 | aa级黄色大片 | 91免费在线 | 视频一区二区在线 | 麻豆 91 在线 | 黄色三级网站在线观看 | 国产小视频福利在线 | 欧美日韩久 | 人人干人人爽 | 超级碰碰碰免费视频 | 亚洲黄色软件 | 最近中文国产在线视频 | 亚洲更新最快 | 国产伦精品一区二区三区在线 | 91精品视频在线免费观看 | 在线视频中文字幕一区 | 黄色免费网站大全 | 99色在线观看 | 亚洲更新最快 | 黄色日批网站 | 国产黄色片免费在线观看 | 9免费视频 | 日韩 在线| 国产一级二级在线播放 | 日韩网| 日韩字幕在线观看 | 亚洲视频h | 深夜免费小视频 | 视频1区2区 | 五月天综合网站 | 久久久久久高潮国产精品视 | 激情一区二区三区欧美 | 国产成人一区二区三区在线观看 | 天天射天天爱天天干 | 日本爽妇网 | 色婷婷97| 久久精品欧美 | 97超碰人人模人人人爽人人爱 | 成人影视免费 | 97超碰在 | 国产精品入口66mio女同 | 国产精品免费观看在线 | 中文字幕中文字幕在线中文字幕三区 | 在线亚洲激情 | 国产一区二区在线观看免费 | 欧美福利视频一区 | 久操视频在线播放 | 日本婷婷色 | www久| 国内揄拍国内精品 | 五月激情站| 麻豆国产精品视频 | 精品国产一区二区三区久久久久久 | 插综合网 | 色综合久久久久久久久五月 | 五月天六月色 | 国内一级片在线观看 | 亚洲婷婷综合色高清在线 | 视频一区二区视频 | 亚洲一级二级三级 | 在线观看黄色小视频 | 亚洲涩涩网站 | 99久久99久久综合 | 91精品国产99久久久久久久 | 黄网站色成年免费观看 | 精品国产综合区久久久久久 | 四虎永久视频 | 天天操天天添天天吹 | 国产成人一区二区三区电影 | 99久久久国产精品免费99 | 国产精品自产拍 | 丁香影院在线 | 狠狠干激情 | 天天操天天吃 | 亚洲国内精品在线 | 天天综合久久 | 99 色 | 亚洲精品视频在线播放 | 丁香激情五月 | 国产老妇av | 不卡的av| 麻豆免费在线播放 | 99精品在线免费 | 国产综合在线视频 | 亚洲 欧美 精品 | 亚洲国产三级在线 | 亚洲综合干 | 久久人人做 | 成人动漫精品一区二区 | 97视频人人澡人人爽 | 亚洲国产午夜精品 | 色天天| 日韩免费视频线观看 | 在线天堂v | 欧美日韩视频 | 夜夜爱av | 日韩二区三区 | 在线视频区| 91精品久久久久久综合五月天 | 国产精品久久久一区二区 | 国产精品自产拍 | 怡红院av | 麻豆精品在线 | 婷婷激情av | 成人一级在线 | a级国产乱理论片在线观看 特级毛片在线观看 | 色婷婷视频网 | av中文在线影视 | 国产精品久久久久久久久费观看 | 欧美在线视频a | www.天天干 | 国产精品一区二区精品视频免费看 | 91资源在线播放 | 国产精品久久久久久久久久东京 | 91成人免费观看视频 | avcom在线 | 国产精品亚洲片在线播放 | 超碰97.com | 日日夜夜草 | 97在线影院 | 在线免费亚洲 | 精品久久久久国产 | 久久兔费看a级 | 日韩在线不卡av | 有码中文在线 | 日日夜夜天天射 | 人人澡人人草 | 国产高清在线一区 | 丁香导航| 狠狠色伊人亚洲综合网站色 | 国产成人一区二区三区久久精品 | 免费a一级 | 久久久久伊人 | 午夜神马福利 | 精品高清美女精品国产区 | 中文字幕乱码视频 | 激情婷婷综合 | 天天干,天天射,天天操,天天摸 | 日本亚洲国产 | 久草在线精品观看 | 免费观看一区二区三区视频 | 亚洲精品在线播放视频 | 久久久久久视频 | 草久在线观看视频 | 亚洲午夜精品电影 | 精品视频久久久久久 | 亚洲精品黄色 | av在线收看 | 韩国av免费| 91精品国产福利在线观看 | 超碰97.com | 国产精品自在线 | 亚洲天堂网视频在线观看 | 日韩在线视频一区二区三区 | 波多野结衣动态图 | 国模视频一区二区三区 | 亚洲精品日韩av | 日韩精品一区二区三区外面 | 精品一区二区精品 | 性色av一区二区三区在线观看 | 亚洲污视频 | 激情在线五月天 | 久久国产精品99国产 | 国产精品精品久久久久久 | 久久婷综合 | 久久久国产精品网站 | 在线看国产 | 欧美日本在线观看视频 | 97精品国产97久久久久久免费 | av成人动漫 | 二区三区在线 | 国产一区久久 | 日韩电影在线观看一区 | 国产精品wwwwww | 国产在线精品福利 | av成人免费 | 免费中午字幕无吗 | 亚州性色 | 免费网站色 | 免费看的av片 | 中文字幕免费观看视频 | 胖bbbb搡bbbb擦bbbb | 91视频下载 | 91av在线不卡 | 国产成人精品一区二区三区福利 | 久久激情网站 | 狠狠狠色丁香婷婷综合久久五月 | 好看av在线 | 国产精品久久久久久久久久了 | 国产福利电影网址 | 中文字幕色播 | 精品a视频| 亚洲精品在线网站 | 在线观看电影av | 视频91| 国产又粗又猛又爽又黄的视频先 | 黄色免费电影网站 | 久久免费的精品国产v∧ | 欧美日韩高清免费 | 国产在线视频一区二区三区 | 天无日天天操天天干 | 人人干天天干 | 国产精品99蜜臀久久不卡二区 | 日韩激情三级 | 国产午夜三级一区二区三 | 中文字幕在线一二 | 狠狠躁日日躁夜夜躁av | 国产九九在线 | 毛片一级免费一级 | 五月天高清欧美mv | 亚洲精品视频第一页 | 91成人网在线播放 | 国产伦理久久 | 欧美国产三区 | 黄色亚洲片 | 99在线视频播放 | 99热99re6国产在线播放 | 亚洲国产视频网站 | 九九久久国产 | 免费成人黄色av | 欧美做受高潮 | 国产一区免费视频 | 亚洲成人精品久久久 | 久久综合狠狠综合久久狠狠色综合 | 日韩免费在线观看视频 | 日韩三级.com | 亚洲精品视频第一页 | 综合婷婷久久 | 亚洲免费精彩视频 | 国产精品免费视频网站 | 97超碰人人澡 | 国产精品毛片久久久久久久久久99999999 | 亚洲精品视频在线播放 | 91网免费观看 | 欧美日韩视频一区二区三区 | 色婷婷婷| 亚洲成人精品国产 | 色香蕉在线 | 美女免费视频一区 | 久久精品视频在线免费观看 | 欧美日韩中文在线观看 | 在线综合 亚洲 欧美在线视频 | 丁香激情婷婷 | av在线免费播放 | 国产在线观看xxx | 97色在线观看免费视频 | 最近中文字幕大全 | 特级西西www44高清大胆图片 | 中文字幕在线观看91 | 在线精品亚洲 | www欧美日韩 | 六月婷婷久香在线视频 | 麻豆视频免费看 | 亚洲精品456在线播放第一页 | 五月天婷亚洲天综合网鲁鲁鲁 | 伊甸园永久入口www 99热 精品在线 | 中文字幕一区二 | 国产精品乱码久久久久久1区2区 | www九九热| 国产精品区二区三区日本 | 九九免费在线观看视频 | 91桃色在线免费观看 | 婷婷亚洲综合五月天小说 | 久久www免费视频 | 超碰人人99 | 在线观看国产高清视频 | 久久久久久久久久久影院 | 欧美午夜久久久 | 999久久久免费精品国产 | 亚洲高清视频在线观看免费 | 中文字幕亚洲欧美日韩 | 欧美久久久久久久久久久 | 正在播放日韩 | 欧美精品在线视频观看 | 日日精品 | 激情五月婷婷激情 | 久久国产精品系列 | 久久久亚洲精华液 | 日韩成人黄色 | 日韩在线网址 | 麻豆成人小视频 | 日本午夜在线亚洲.国产 | 久久国产精品电影 | 亚洲日本色| av片一区二区 | 午夜影院一级 | 国产精品成人av电影 | 免费网站观看www在线观看 | 欧美日韩在线观看一区二区 | 99久久精品国产免费看不卡 | 国产 欧美 日产久久 | 天天综合在线观看 | 国产成人在线免费观看 | 在线91av| 久久69精品 | 操老逼免费视频 | 国产一级片一区二区三区 | 狠狠的日日 | 国产第一页精品 | 中文字幕在线网 | 天天操夜夜操天天射 | 国产精品免费在线播放 | 亚洲国产福利视频 | 91精品电影 | 在线观看mv的中文字幕网站 | 欧美巨大| 超碰在线91| 免费看短 | 在线观看完整版免费 | 最新婷婷色 | 人人澡人人爽欧一区 | a特级毛片 | 99精品欧美一区二区蜜桃免费 | 国产一区久久久 | 一级一片免费看 | 久久午夜电影院 | 亚洲国产中文字幕在线观看 | 精品亚洲在线 | 久久久久久久av | 中文字幕日本特黄aa毛片 | 又黄又爽又无遮挡的视频 | 九九综合久久 | 免费精品视频在线观看 | 91在线你懂的 | 黄色app网站在线观看 | 18av在线视频 | 亚洲影音先锋 | 最近日本中文字幕a | 五月婷婷一区 | 免费观看日韩 | 中国一级特黄毛片大片久久 | 日韩激情小视频 | 久久情爱 | 99在线视频免费观看 | 亚洲成人软件 | 99爱在线观看 | 久久久久国产成人精品亚洲午夜 | 国产中文字幕一区二区三区 | 日韩在线网址 | 国产专区一 | 国产精品大全 | 午夜免费在线观看 | 亚洲网站在线看 | 在线播放国产一区二区三区 | 日日天天狠狠 | 成人a级免费视频 | 日韩免费在线观看 | 波多野结衣一区三区 | 在线观看国产www | 中文字幕国产 | 六月婷操 | 国产亚洲观看 | 美女视频一区二区 | 日韩免费视频播放 | 久草在线免费看视频 | 久久久久久影视 | 国产美女精彩久久 | 99这里有精品 | 免费在线黄色av | 黄色福利网站 | 亚洲自拍自偷 | 国产欧美三级 | 亚洲理论电影 | 不卡av免费在线观看 | 亚洲精品乱码久久久久久高潮 | 久久中文字幕在线视频 | 综合久久精品 | 久久99精品一区二区三区三区 | 久久视频在线免费观看 | 国产一卡久久电影永久 | 天天插视频 | 色天天综合网 | 免费亚洲一区二区 | 欧美性色综合 | 午夜av电影院 | www天天操| 久草在线欧美 | 久久r精品| 亚洲国产97在线精品一区 | 99精品在线播放 | 久久激情视频免费观看 | 久久永久免费 | 欧美性色综合网 | 日本久久久精品视频 | 久久久久久久久久久久久国产精品 | 日韩成人xxxx | 五月天视频网站 | 日本不卡一区二区三区在线观看 | 在线观看日韩一区 | 少妇bbw搡bbbb搡bbb | 99在线观看视频网站 | 999久久久国产精品 高清av免费观看 | 久久96国产精品久久99软件 | 中文字幕在线观看免费高清完整版 | 午夜视频二区 | 全黄网站 | 黄色片视频免费 | 日韩精品不卡在线观看 | 91av视屏| 粉嫩av一区二区三区四区五区 | 国产日本在线观看 | 欧美精选一区二区三区 | 91成人精品在线 | 国产99久久精品一区二区300 | 欧美a免费| 久久午夜影院 | 香蕉视频免费在线播放 | 人人爽人人干 | 一本到在线 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 久久99中文字幕 | 中文字幕资源在线观看 | 久草手机视频 | 国产精品久久久久久久免费大片 | 亚洲一区不卡视频 | 精品国内自产拍在线观看视频 | 91av在线播放视频 | 亚洲视频在线观看 | www.色午夜.com | 91九色视频网站 | 成人黄色在线视频 | 欧美一区二区三区免费观看 | 香蕉影视在线观看 | 久久久久久黄色 | 丁香六月婷婷开心婷婷网 | 亚洲人视频在线 | 免费观看久久久 | 久久精品91视频 | 天堂av中文字幕 | 九九久久电影 | 久久精品美女视频网站 | 男女啪啪免费网站 | 亚洲国产精品免费 | 国产免费久久久久 | 国产精品永久免费 | 亚洲午夜久久久久久久久电影网 | 久草资源在线 | 国产色婷婷精品综合在线手机播放 | 久草在线 | 久久综合婷婷国产二区高清 | 少妇自拍av| 国产亚洲va综合人人澡精品 | 九九99| 久操视频在线免费看 | 久久国产精品网站 | 国产精品久久久久久高潮 | 青青草在久久免费久久免费 | 综合精品在线 | 成人毛片100免费观看 | 亚洲 精品在线视频 | 欧美在线视频第一页 | 国产精品免费久久久久影院仙踪林 | 精品国产亚洲在线 | 亚洲精品影视在线观看 | 成人h视频在线播放 | 久久久久久久久久久久av | 久久久免费看视频 | 视频一区二区国产 | 免费国产一区二区视频 | 麻花豆传媒mv在线观看 | 夜夜操天天 | 欧美a级一区二区 | 国产精品综合在线观看 | 国产精品精品国产色婷婷 | 青青河边草免费观看完整版高清 | 久久任你操| 久久综合五月 | 免费av免费观看 | 久久极品| 午夜在线国产 | 久久国产精品免费 | 欧美天天综合网 | 久久国产乱 | 韩国av不卡 | 国产区精品 | 婷婷色在线 | 国产一区二区在线免费观看 | www.黄色小说.com | 深爱激情婷婷网 | 天天插狠狠干 | 91人人视频在线观看 | 韩国精品视频在线观看 | 日韩在线视频观看免费 | 天天操月月操 | 丁香婷婷久久 | 免费网站在线观看人 | 久久婷婷五月综合色丁香 | 91亚洲欧美激情 | 91中文字幕在线播放 | 中文字幕免费不卡视频 | 国产免费不卡av | 在线电影 一区 | 欧洲av在线 | 日韩中文字幕免费在线播放 | 狠狠的操狠狠的干 | 韩国在线一区二区 | 久久久久久欧美二区电影网 | 激情婷婷网 | 日韩精品在线观看视频 | 婷婷色网视频在线播放 | 中文字幕 国产视频 | 色多多视频在线 | 久久曰视频 | 97电影网站 | 欧美激情第一页xxx 午夜性福利 | 伊人小视频 | 日韩精品大片 | 国产成人精品综合 | 欧美二区视频 | 国产在线日本 | 操操操av | 亚洲欧洲中文日韩久久av乱码 | 激情在线网址 | 91精品视频在线看 | 亚洲视频 一区 | 中文网丁香综合网 | 精品一区二区免费在线观看 | 久久久99精品免费观看 | 91亚洲精品久久久蜜桃网站 | 在线黄网站 | 国产亚洲情侣一区二区无 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 丝袜制服综合网 | wwwav视频 | 久草免费看 | 亚洲免费精品一区二区 | 综合亚洲视频 | 欧美激情奇米色 | 国产伦理剧| 欧美大码xxxx | 日韩中文字幕a | 女人久久久久 | 日本性xxxxx| 国产免费xvideos视频入口 | 黄色一及电影 | 成年人黄色免费看 | 日韩一区二区三区在线观看 | 久久久久久黄色 | 国产精品久久久久久久久蜜臀 | 国产精品免费在线播放 | 欧美激情第十页 | 五月婷婷综合网 | 日韩午夜在线观看 | 国产小视频福利在线 | 水蜜桃亚洲一二三四在线 | 久久精品一二区 | 国产精品久久久一区二区三区网站 | 免费福利片2019潦草影视午夜 | 天天操夜夜摸 | 国产激情电影综合在线看 | 免费在线观看av | 日韩欧美一区二区三区在线 | 激情 婷婷 | japanese黑人亚洲人4k | 婷婷夜夜 | 免费看成人a | 国产成人在线播放 | 色www永久免费 | 久久久久久久久久久久久国产精品 | 中文字幕第 | 亚洲精品在线观看网站 | 天天曰夜夜操 | 狠狠色噜噜狠狠狠狠2021天天 | 色综合久久久久综合体桃花网 | 国产精品 999 | 国产 日韩 欧美 在线 | 欧美日韩在线精品一区二区 | 国产一在线精品一区在线观看 | 99理论片 | 免费视频一级片 | 国内精品小视频 | 亚洲激情在线观看 | 婷婷播播网 | 免费看毛片网站 | 欧美日韩国产在线 | 色噜噜狠狠狠狠色综合 | 夜夜躁日日躁狠狠久久88av | 免费99精品国产自在在线 | 免费h漫在线观看 | 91久久久国产精品 | 三级a视频 | 91av在线电影 | 五月天久久狠狠 | 久久av免费电影 | 久久一区二区三区超碰国产精品 | 中文字幕一区二区三区在线播放 | 国产特级毛片 | 国产操在线 | 久久精品爱视频 | av导航福利 | 免费一级片在线观看 | 亚洲国产精品va在线看黑人动漫 | 国产精品久久久久久久婷婷 | 日韩深夜在线观看 | 国产欧美日韩视频 | 天天操天天透 | www最近高清中文国语在线观看 | 午夜久久福利 | 青青草华人在线视频 | 黄色中文字幕在线 | 久免费 | 99精品区| 男女激情网址 | 欧美日韩久久不卡 | 国产美女精彩久久 | 中文字幕一区二区三区四区 | 国产精品成人一区二区 | 最近中文字幕完整高清 | 中文字幕一区二区三区在线观看 | 国产第一二区 | 91精品国产综合久久福利不卡 | 91在线www | 欧美激情第28页 | 日韩免费福利 | 免费看毛片在线 | 久久精品免视看 | 欧美最新大片在线看 | 黄色毛片一级 | 五月综合激情婷婷 | 久久久久久久久电影 | 亚洲精品欧美视频 | 中文字幕之中文字幕 | av在线播放快速免费阴 | 久久精彩免费视频 | 久久 在线 | 成人免费共享视频 | 中文字幕国内精品 | 三级黄色免费 | 精品国产一区二区三区四 | 中文字幕久久网 | 色先锋资源网 | 亚洲精品午夜国产va久久成人 | 97在线观 | 亚洲精品久久久久58 | 一本一本久久a久久精品综合小说 | 精品国产亚洲在线 | 91在线成人 | 亚洲日日日 | 色综合久久66 | 在线精品亚洲 | 狠狠色狠狠色综合日日小说 | 又色又爽又黄 | 成人av电影在线 | 国产精品美女999 | 99视频精品在线 | 毛片永久新网址首页 | 日日躁夜夜躁xxxxaaaa | 又爽又黄又刺激的视频 | 中文字幕在线免费 | 在线播放你懂 | 成人免费在线观看av | 亚洲成av片人久久久 | 一区二区三区精品在线视频 | 亚洲一区网 | 麻豆av电影 | 国产在线超碰 | 国产精品免费久久久 | 色婷婷狠狠18 | 亚洲成年人免费网站 | 97超碰人人澡人人爱 | 欧美 亚洲 另类 激情 另类 | 久久首页 | 亚洲精品国产片 | 国产精品黄网站在线观看 | 久久伦理| 91久草视频 | 91精彩视频 | 欧美激情视频一区二区三区 | 久久久高清| 国产精品久久久免费看 | 国产中文字幕国产 | 亚洲精品国产自产拍在线观看 | 九九久久久 | 精品久久久免费视频 | 有码中文字幕在线观看 | 亚洲精品国产精品国自产在线 | 国产精品女主播一区二区三区 | 2023av| 99精品免费久久久久久久久 | 国产91aaa| 最近中文字幕第一页 | 精品视频在线观看 | 香蕉视频4aa | 欧美久久久久久久久久久 | 日韩女同一区二区三区在线观看 | 国产香蕉在线 | 一区二区三区三区在线 | 一区二区三区动漫 | 91亚洲精品久久久久图片蜜桃 | 久草在线久草在线2 | 超碰com| 色综合天天色 | 99草在线视频 | 成人在线免费观看网站 | 中文字幕av播放 | 国产精品手机看片 | 免费看成人 | 亚洲丝袜一区二区 | 亚洲精品午夜视频 | av大片免费在线观看 | 中文字幕亚洲欧美日韩2019 | 在线播放第一页 | www.91成人 | 亚洲精品视频网 | 中文字幕在线日亚洲9 | 免费无遮挡动漫网站 | 在线小视频你懂的 | 一级a性色生活片久久毛片波多野 | 少妇bbb搡bbbb搡bbbb′ | 在线观看涩涩 | 国产精品美 | 欧美日韩视频网站 | 91探花在线视频 | 精品中文字幕在线播放 | 免费黄色在线播放 | 久久综合九色综合欧美就去吻 | 九九综合九九 | 国产精品乱码高清在线看 | 久青草电影 | 国产护士在线 | 国产精品地址 | 亚洲激情综合网 | 欧美日韩精品免费观看 | 国产自制av| www五月| 四虎国产精品免费观看视频优播 | 精品久久久久一区二区国产 | 最新日韩中文字幕 | 韩国一区视频 | 国产中文字幕久久 | 99久免费精品视频在线观看 | 男女拍拍免费视频 | 国产精品成人国产乱一区 | 国产日韩高清在线 | 麻花豆传媒mv在线观看网站 | 五月天中文字幕 | 国产破处在线播放 | 色在线免费观看 | 亚洲成人av电影在线 | 日韩精品五月天 | 国产综合精品一区二区三区 | 麻豆成人网 | av福利资源| 日韩精品免费一区二区 | 日批在线观看 | 香蕉手机在线 | 成人免费在线观看av | 黄色中文字幕 | 高清av在线免费观看 | 激情久久久久久久久久久久久久久久 | 在线日韩中文字幕 | 婷婷中文在线 | 玖玖在线观看视频 | 国产免费观看av | 亚洲最大在线视频 | 国产亚洲精品综合一区91 | 日韩电影一区二区在线观看 | 亚洲三级av| 国产亚洲精品bv在线观看 | 日韩免费不卡av | 亚州国产精品久久久 | 久久久久成人精品 | 国产中文字幕在线看 | 国产麻豆成人传媒免费观看 | 国产99久| 天无日天天操天天干 | 一级特黄av| 国产无遮挡猛进猛出免费软件 | 狠狠干天天| 正在播放国产一区二区 | 国产精品视频免费观看 | 黄色精品一区 | 91精品国产91久久久久 | 在线看国产日韩 | 欧美韩国在线 | 91亚洲网| 国产精品 日韩 | 色婷婷综合久色 | 日韩成人一级大片 | 免费在线a | 欧美成人播放 | 一区二区精品国产 | 欧美日韩国产一区二区三区 | 免费观看全黄做爰大片国产 | 国产日韩欧美视频在线观看 | 天天爽天天碰狠狠添 | 亚洲午夜精品久久久久久久久久久久 | 国产精品九九视频 | 婷婷色在线观看 | 久久久精品网 | 草久久久久久 | 久久在草| 久热久草在线 | 欧美成天堂网地址 | 欧美一区二区免费在线观看 | 日本丶国产丶欧美色综合 | 五月婷婷在线视频观看 | 狠狠躁夜夜a产精品视频 | 91视频com| 日韩精品亚洲专区在线观看 | 四虎影视av | 91视频在线免费 | 精品字幕在线 | 日韩欧美在线综合网 | 久久男人视频 | 欧美精品一区二区蜜臀亚洲 | 色狠狠久久av五月综合 | 成人毛片在线观看 | 黄色在线观看www | 久久综合亚洲鲁鲁五月久久 | 国产中出在线观看 | 亚洲电影图片小说 | 美国av片在线观看 | 亚洲永久字幕 | 综合久久影院 | 久草在线精品观看 | 国产精品永久在线观看 | 国产高清永久免费 | 99视频国产精品免费观看 | 亚洲国产免费av | 黄色一级大片免费看 | 有没有在线观看av | 欧美人操人 | 国产综合小视频 | 五月婷婷六月丁香激情 | 久99久中文字幕在线 | 麻豆免费看片 | 黄网站www| 99色99| 六月激情 | 国产在线理论片 |