建設(shè)網(wǎng)站裝配式建筑樓房/百度官網(wǎng)網(wǎng)頁版
背景
最近項目業(yè)務(wù),所有模塊已經(jīng)支持Swift混編開發(fā),正在逐步使用Swift 方式進行開發(fā)新業(yè)務(wù),以及逐步替換老業(yè)務(wù)方式進行發(fā)展,所以使用一些較為成熟的Swift 的三方庫,成為必要性,經(jīng)過調(diào)研發(fā)現(xiàn)RxSwift 在使用的情況上,較為成熟,且方便實用;以下介紹一些RxSwift 使用的一些方式和大家一起學(xué)習(xí)討論
Swift為值類型,在傳值與方法回調(diào)上有影響,RxSwift一定程度上彌補Swift的靈活性
- RxSwift使得代碼復(fù)用性較強,減少代碼量
- RxSwift因為聲明都是不可變更,增加代碼可讀性
- RxSwift使得更易于理解業(yè)務(wù)代碼,抽象異步編程,統(tǒng)一代碼風(fēng)格
- RxSwift使得代碼更易于編寫集成單元測試,增加代碼穩(wěn)定性
一:簡單的使用方式
1.1 信號創(chuàng)建
1.1.1創(chuàng)建一個普通信號
let disposeB = DisposeBag()//通過指定的方法實現(xiàn)來自定義一個被觀察的序列。//訂閱創(chuàng)建let myOb = Observable<Any>.create { (observ) -> Disposable inobserv.onNext("alan")observ.onCompleted()return Disposables.create()}//訂閱事件myOb.subscribe { (even) inprint("subscribe" + "\(even)")}.disposed(by: disposeB)//銷毀1.1.2 創(chuàng)建信號的其他方式class ViewController: UIViewController {let disposeB = DisposeBag()override func viewDidLoad() {super.viewDidLoad()// Do any additional setup after loading the view, typically from a nib.//通過指定的方法實現(xiàn)來自定義一個被觀察的序列。//訂閱創(chuàng)建let myOb = Observable<Any>.create { (observ) -> Disposable inobserv.onNext("alan")zipSigal observ.onCompleted()return Disposables.create()}//訂閱事件myOb.subscribe { (even) inprint("subscribe" + "\(even)")}.disposed(by: disposeB)//銷毀//各種觀察者序列產(chǎn)生方式//該方法通過傳入一個默認值來初始化。Observable.just("just").subscribe { (event) inprint(event)}.disposed(by: disposeB)//該方法可以接受可變數(shù)量的參數(shù)(必需要是同類型的)Observable.of("o","f","of").subscribe { (event) inprint(event)}.disposed(by: disposeB)//該方法需要一個數(shù)組參數(shù)。Observable.from(["f","r","o","m"]).subscribe { (event) inprint("from" + "\(event)")}.disposed(by: disposeB)//該方法創(chuàng)建一個永遠不會發(fā)出 Event(也不會終止)的 Observable 序列。Observable<Int>.never().subscribe { (event) inprint(event)}.disposed(by: disposeB)// // 該方法創(chuàng)建一個空內(nèi)容的 Observable 序列。 //會打印completeObservable<Int>.empty().subscribe { (event) inprint("empty" ,event)}.disposed(by: disposeB)//該方法創(chuàng)建一個不做任何操作,而是直接發(fā)送一個錯誤的 Observable 序列。let myError = MyError.Aprint(myError.errorType)Observable<Int>.error(myError).subscribe { (event) inprint(event.error)}.disposed(by: disposeB)//該方法通過指定起始和結(jié)束數(shù)值,創(chuàng)建一個以這個范圍內(nèi)所有值作為初始值的Observable序列。Observable.range(start: 1, count: 6).subscribe { (event) inprint(event)}.disposed(by: disposeB)//該方法創(chuàng)建一個可以無限發(fā)出給定元素的 Event的 Observable 序列(永不終止)。慎重使用// Observable.repeatElement("SPAlan").subscribe { (event) in// print(event)// }.disposed(by: disposeB)//該方法創(chuàng)建一個只有當(dāng)提供的所有的判斷條件都為 true 的時候,才會給出動作的 Observable 序列。//第一個參數(shù):初始化的數(shù)值 第二個 條件 第三也是一個條件 0 + 2 <= 10 依次循環(huán)下去,iterate:重復(fù)執(zhí)行 ,執(zhí)行結(jié)果為 0,2,4,6,8,10Observable.generate(initialState: 0, condition: {$0<=10}, iterate: {$0+2}).subscribe { (event) inprint(event)}.disposed(by: disposeB)//上面和下面的效果一樣Observable.of(0,2,4,6,8,10).subscribe { (event) inprint(event)}.disposed(by: disposeB)//該個方法相當(dāng)于是創(chuàng)建一個 Observable 工廠,通過傳入一個 block 來執(zhí)行延遲 Observable序列創(chuàng)建的行為,而這個 block 里就是真正的實例化序列對象的地方。var isOdd = truelet factory: Observable<Int> = Observable.deferred { () -> Observable<Int> inisOdd = !isOddif isOdd{return Observable.of(0,2,4,6,8)}else{return Observable.of(1,3,5,7,9)}}//這里會調(diào)用上面的工廠factory.subscribe { (event) inprint("\(isOdd)",event)}.disposed(by: disposeB)//這里會再次調(diào)用工廠factory.subscribe { (event) inprint("\(isOdd)",event)}.disposed(by: disposeB)//這個方法創(chuàng)建的 Observable 序列每隔一段設(shè)定的時間,會發(fā)出一個索引數(shù)的元素。而且它會一直發(fā)送下去。// Observable<Int>.interval(DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance).subscribe { (event) in// print(event)// }.disposed(by: disposeB)//這個方法有兩種用法,一種是創(chuàng)建的 Observable序列在經(jīng)過設(shè)定的一段時間后,產(chǎn)生唯一的一個元素。,這個只調(diào)用一次Observable<Int>.timer(DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance).subscribe{(event) inprint("123",event)}.disposed(by: disposeB)//另一種是創(chuàng)建的 Observable 序列在經(jīng)過設(shè)定的一段時間后,每隔一段時間產(chǎn)生一個元素。:經(jīng)過5秒后每個1秒創(chuàng)建一個元素// Observable<Int>.timer(DispatchTimeInterval.seconds(5), period: DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance).subscribe { (event) in// print(event)// }.disposed(by: disposeB)}enum MyError:Error {case Acase Bvar errorType:String {switch self {case .A:return "i am error A"case .B:return "BBBB"}}}override func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated.}}
1.2 iOS中的一些用法
1.2.1:button點擊事件
//MARK: - RxSwift應(yīng)用-button響應(yīng)func setupButton() {// 業(yè)務(wù)邏輯 和 功能邏輯// 設(shè)計self.button.rx.tap.subscribe(onNext: { () inprint("按鈕點擊了")}).disposed(by: disposeBag)}
1.2.2:textfiled文本響應(yīng)
//MARK: - RxSwift應(yīng)用-textfiledfunc setupTextFiled() {self.textFiled.rx.text.orEmpty.subscribe(onNext: { (text) inprint(text)}).disposed(by: disposeBag)// 簡單簡單 更簡單-RxSwift 面向開發(fā)者self.textFiled.rx.text.bind(to: self.button.rx.title()).disposed(by: disposeBag)}
1.2.3:scrollView效果
//MARK: - RxSwift應(yīng)用-scrollViewfunc setupScrollerView() {scrollView.contentSize = CGSize(width: 300, height: 1000)scrollView.rx.contentOffset.subscribe(onNext: { [weak self](content) inprint(content);print(self?.scrollView)}).disposed(by: disposeBag)}
1.2.4:KVO
//MARK: - RxSwift應(yīng)用-KVOfunc setupKVO() {// 系統(tǒng)KVO 還是比較麻煩的// person.addObserver(self, forKeyPath: "name", options: .new, context: nil)person.rx.observeWeakly(String.self, "name").subscribe(onNext: { (change) inprint(change ?? "helloword")}).disposed(by: disposeBag)}
1.2.5:通知
//MARK: - 通知func setupNotification(){NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification).subscribe { (event) inprint(event)}.disposed(by: disposeBag)}
1.2.6:手勢
//MARK: - 手勢func setupGestureRecognizer(){let tap = UITapGestureRecognizer()self.label.addGestureRecognizer(tap)self.label.isUserInteractionEnabled = truetap.rx.event.subscribe(onNext: { (tap) inprint(tap.view)}).disposed(by: disposeBag)}
1.2.7:網(wǎng)絡(luò)請求
//MARK: - RxSwift應(yīng)用-網(wǎng)絡(luò)請求func setupNextwork() {let url = URL(string: "https://www.baidu.com")// 傳統(tǒng)方式URLSession.shared.dataTask(with: url!) { (data, response, error) inprint("dataTask.response->" + "\(response)")print("dataTask.response->" + "\(data)")}.resume()//RxSwift 方式URLSession.shared.rx.response(request: URLRequest(url: url!)).subscribe(onNext: { (response, data) inprint("rx.response.response ==== \(response)")print("rx.response.data ===== \(data)")}, onError: { (error) inprint("error ===== \(error)")}).disposed(by: disposeBag)}
1.2.8:timer定時器
func setupTimer() {timer = Observable<Int>.interval(DispatchTimeInterval.seconds(1), scheduler: MainScheduler.instance)timer.subscribe(onNext: { (num) inprint("hello word \(num)")}).disposed(by: disposeBag)}
二:高階用法
2.1:組合操作符
2.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
2.1.2:merge
print("*****merge*****")let subject1 = PublishSubject<String>()let subject2 = PublishSubject<String>()// merge subject1和subject2Observable.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")
2.1.3:zip
- 將多達8個原可觀測序列組合成一個新的可觀測序列,并將從組合的可觀測序列中發(fā)射出對應(yīng)索引處每個原可觀測序列的元素
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 但是不會響應(yīng)除非;另一個響應(yīng)intSubject.onNext(1) // 勾出一個intSubject.onNext(2) // 勾出另一個stringSubject.onNext("i") // 存一個intSubject.onNext(3) // 勾出一個// 說白了: 只有兩個序列同時有值的時候才會響應(yīng),否則存值
2.1.4:combineLatest
- 將原可觀測序列組合成一個新的觀測序列,并將開始發(fā)出聯(lián)合觀測序列的每個元素最新元素可觀測序列一旦所有排放原序列至少有一個元素,并且當(dāng)原可觀測序列發(fā)出的任何一個新元素
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("S") // 存一個 SstringSub.onNext("P") // 存了一個覆蓋 - 和zip不一樣intSub.onNext(1) // 發(fā)現(xiàn)strOB也有G 響應(yīng) G 1intSub.onNext(2) // 覆蓋1 -> 2 發(fā)現(xiàn)strOB 有值G 響應(yīng) G 2stringSub.onNext("alan") // 覆蓋G -> alan 發(fā)現(xiàn)intOB 有值2 響應(yīng) alan 2// combineLatest 比較zip 會覆蓋// 應(yīng)用非常頻繁: 比如賬戶和密碼同時滿足->才能登陸. 不關(guān)系賬戶密碼怎么變化的只要查看最后有值就可以 loginEnable輸出結(jié)果:*****combineLatest*****P 1P 2alan 2
2.1.5:switchLatest
- 將可觀察序列發(fā)出的元素轉(zhuǎn)換為可觀察序列,并從最近的內(nèi)部可觀察序列發(fā)出元素
print("*****switchLatest*****")let switchLatestSub1 = BehaviorSubject(value: "L")let switchLatestSub2 = BehaviorSubject(value: "1")let switchLatestSub = BehaviorSubject(value: switchLatestSub1)// 選擇了 switchLatestSub1 就不會監(jiān)聽 switchLatestSub2switchLatestSub.asObservable().switchLatest().subscribe(onNext: { print($0) }).disposed(by: disposeBag)switchLatestSub1.onNext("G")switchLatestSub1.onNext("_")switchLatestSub2.onNext("2")switchLatestSub2.onNext("3") // 2-3都會不會監(jiān)聽,但是默認保存由 2覆蓋1 3覆蓋2switchLatestSub.onNext(switchLatestSub2) // 切換到 switchLatestSub2switchLatestSub1.onNext("*")switchLatestSub1.onNext("alan") // 原理同上面 下面如果再次切換到 switchLatestSub1會打印出 alanswitchLatestSub2.onNext("4")輸出結(jié)果為:*****switchLatest*****LG_34
2.2:映射操作符
2.2.1:map
- 轉(zhuǎn)換閉包應(yīng)用于可觀察序列發(fā)出的元素,并返回轉(zhuǎn)換后的元素的新可觀察序列。
print("*****map*****")let ob = Observable.of(1,2,3,4)ob.map { (number) -> Int inreturn number+2}.subscribe{print("\($0)")}.disposed(by: disposeBag)
2.2.2:flatMap and flatMapLatest
- 將可觀測序列發(fā)射的元素轉(zhuǎn)換為可觀測序列,并將兩個可觀測序列的發(fā)射合并為一個可觀測序列。
- 這也很有用,例如,當(dāng)你有一個可觀察的序列,它本身發(fā)出可觀察的序列,你想能夠?qū)θ魏我粋€可觀察序列的新發(fā)射做出反應(yīng)(序列中序列:比如網(wǎng)絡(luò)序列中還有模型序列)
- flatMap和flatMapLatest的區(qū)別是,flatMapLatest只會從最近的內(nèi)部可觀測序列發(fā)射元素
struct SPPlayer {var score: BehaviorRelay<Int>}func flatMapLatest(){print("*****flatMapLatest*****")var boy = SPPlayer(score: BehaviorRelay(value: 100))var girl = SPPlayer(score: BehaviorRelay(value: 90))var player = BehaviorSubject(value: boy)player.asObservable().flatMapLatest{$0.score.asObservable() } // 本身score就是序列 模型就是序列中的序列.subscribe(onNext: { print($0) }).disposed(by: disposeBag)boy.score.accept(75)player.onNext(girl)boy.score.accept(50)boy.score.accept(40)// 如果切換到 flatMapLatest 就不會打印girl.score.accept(10)girl.score.accept(0)// 輸出結(jié)果為:100,75,90,10,0}func flatMap(){print("*****flatMap*****")var boy = SPPlayer(score: BehaviorRelay(value: 100))var girl = SPPlayer(score: BehaviorRelay(value: 90))var player = BehaviorSubject(value: boy)player.asObservable().flatMap {$0.score.asObservable() } // 本身score就是序列 模型就是序列中的序列.subscribe(onNext: { print($0) }).disposed(by: disposeBag)boy.score.accept(75)player.onNext(girl)boy.score.accept(50)boy.score.accept(40)// 如果切換到 flatMapLatest 就不會打印girl.score.accept(10)girl.score.accept(0)// 輸出結(jié)果為:100,75,90,50,40,10,0}
2.2.3:scan
- 從初始就帶有一個默認值開始,然后對可觀察序列發(fā)出的每個元素應(yīng)用累加器閉包,并以單個元素可觀察序列的形式返回每個中間結(jié)果
print("*****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)// 這里主要強調(diào)序列值之間的關(guān)系
2.3:過濾條件操作符
2.3.1:filter
- 僅從滿足指定條件的可觀察序列中發(fā)出那些元素
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)
2.3.2:distinctUntilChanged
- 抑制可觀察序列發(fā)出的順序重復(fù)元素
print("*****distinctUntilChanged*****")Observable.of("1", "2", "2", "2", "3", "3", "4").distinctUntilChanged().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
2.3.3:elementAt
- 僅在可觀察序列發(fā)出的所有元素的指定索引處發(fā)出元素
print("*****elementAt*****")Observable.of("A", "l", "a", "n", "z").element(at: 3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
2.3.4:single
- 只發(fā)出可觀察序列發(fā)出的第一個元素(或滿足條件的第一個元素)。如果可觀察序列發(fā)出多個元素,將拋出一個錯誤。
print("*****single*****")Observable.of("alan", "zhi").single().subscribe(onNext: { print($0) }).disposed(by: disposeBag)Observable.of("zhai", "zhuang").single { $0 == "zhuang" }.subscribe (onNext:{ print($0,"---single---") }).disposed(by: disposeBag)/**輸出結(jié)果:alanUnhandled error happened: Sequence contains more than one element.zhuang ---single---**/
2.3.5:take
- 只從一個可觀察序列的開始發(fā)出指定數(shù)量的元素。 上面signal只有一個序列 在實際開發(fā)會受到局限 這里引出 take 想幾個就幾個
print("*****take*****")Observable.of("alan", "zhuang","xing", "zhai").take(2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
2.3.6:takeLast
- 僅從可觀察序列的末尾發(fā)出指定數(shù)量的元素
print("*****takeLast*****")Observable.of("alan", "zhuang","xing", "zhai").takeLast(3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)//輸出結(jié)果:zhuang xing zhai2.3.7:takeWhile
只要指定條件的值為true,就從可觀察序列的開始發(fā)出元素print("*****takeWhile*****")Observable.of(1, 2, 3, 4, 5, 6).take(while: { int inint < 3}).subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結(jié)果 1,2
2.3.8:takeUntil
- 從原序列可觀察序列發(fā)出元素,直到參考可觀察序列發(fā)出元素
- 這個要重點,應(yīng)用非常頻繁 比如當(dāng)前頁面銷毀了,就不能獲取值了(cell重用運用)
print("*****takeUntil*****")let sourceSequence = PublishSubject<String>()let referenceSequence = PublishSubject<String>()sourceSequence.take(until: referenceSequence).subscribe (onNext:{ print($0) }).disposed(by: disposeBag)sourceSequence.onNext("alan")sourceSequence.onNext("zhai")sourceSequence.onNext("xing")referenceSequence.onNext("zhuang") // 條件一出來,下面就走不了sourceSequence.onNext("qiang")sourceSequence.onNext("yanzi")sourceSequence.onNext("ting")輸出結(jié)果為:*****takeUntil*****alanzhaixing
2.3.9:skip
- 從原序列可觀察序列發(fā)出元素,直到參考可觀察序列發(fā)出元素
- 這個要重點,應(yīng)用非常頻繁 不用解釋?textfiled?都會有默認序列產(chǎn)生
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).skip(while :{int inint < 3}).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
2.3.10:skipUntil
- 抑制從原序列可觀察序列發(fā)出元素,直到參考可觀察序列發(fā)出元素
print("*****skipUntil*****")let sourceSeq = PublishSubject<String>()let referenceSeq = PublishSubject<String>()sourceSeq.skip(until: referenceSeq).subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 沒有條件命令 下面走不了sourceSeq.onNext("alan")sourceSeq.onNext("zhai")sourceSeq.onNext("qiang")referenceSeq.onNext("zhuang") // 條件一出來,下面就可以走了sourceSeq.onNext("lilei")sourceSeq.onNext("yanzi")sourceSeq.onNext("meimei")輸出結(jié)果為:*****skipUntil*****lileiyanzimeimei
2.4:集合控制操作符
2.4.1:toArray
- 將一個可觀察序列轉(zhuǎn)換為一個數(shù)組,將該數(shù)組作為一個新的單元素可觀察序列發(fā)出,然后終止
print("*****toArray*****")Observable.range(start: 1, count: 10).toArray().subscribe(onSuccess: { print($0) }).disposed(by: disposeBag)// 輸出結(jié)果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2.4.2:reduce
- 從一個設(shè)置的初始化值開始,然后對一個可觀察序列發(fā)出的所有元素應(yīng)用累加器閉包,并以單個元素可觀察序列的形式返回聚合結(jié)果 - 類似scan
print("*****reduce*****")Observable.of(10, 100, 1000).reduce(1, accumulator: +) // 1 + 10 + 100 + 1000 = 1111.subscribe(onNext: { print($0) }).disposed(by: disposeBag)// 輸出結(jié)果:1111
2.4.3:concat
- 以順序方式連接來自一個可觀察序列的內(nèi)部可觀察序列的元素,在從下一個序列發(fā)出元素之前,等待每個序列成功終止
print("*****concat*****")let subject1 = BehaviorSubject(value: "zhai")let subject2 = BehaviorSubject(value: "1")let subjectsSubject = BehaviorSubject(value: subject1)subjectsSubject.asObservable().concat().subscribe (onNext:{ print($0) }).disposed(by: disposeBag)subject1.onNext("alan")subject1.onNext("xing")subjectsSubject.onNext(subject2)subject2.onNext("打印不出來")subject2.onNext("2")subject1.onCompleted() // 必須要等subject1 完成了才能訂閱到! 用來控制順序 網(wǎng)絡(luò)數(shù)據(jù)的異步subject2.onNext("3")
2.5:從可觀察對象的錯誤通知中恢復(fù)的操作符
2.5.1:catchAndReturn
- 從錯誤事件中恢復(fù),方法是返回一個可觀察到的序列,該序列發(fā)出單個元素,然后終止
enum SPError:Error {case Acase Bvar errorType:String {switch self {case .A:return "i am error A"case .B:return "BBBB"}}}let spError = SPError.Aprint("*****catchAndReturn*****")let sequenceThatFails = PublishSubject<String>()sequenceThatFails.catchAndReturn("alan").subscribe (onNext: { print($0) }).disposed(by: disposeBag)sequenceThatFails.onNext("qiang")sequenceThatFails.onNext("lilei") // 正常序列發(fā)送成功的//發(fā)送失敗的序列,一旦訂閱到位 返回我們之前設(shè)定的錯誤的預(yù)案sequenceThatFails.onError(self.spError)
5.2:catch
- 通過切換到提供的恢復(fù)可觀察序列,從錯誤事件中恢復(fù)
print("*****catch*****")let sequenceThatFails = PublishSubject<String>()let recoverySequence = PublishSubject<String>()sequenceThatFails.catch {print("Error:", $0)return recoverySequence}.subscribe { print($0) }.disposed(by: disposeBag)sequenceThatFails.onNext("😬")sequenceThatFails.onNext("😨")sequenceThatFails.onNext("😡")sequenceThatFails.onNext("🔴")sequenceThatFails.onError(self.spError)recoverySequence.onNext("😊")5.3:retry
通過無限地重新訂閱可觀察序列來恢復(fù)重復(fù)的錯誤事件print("*****retry*****")var count = 1 // 外界變量控制流程let sequenceRetryErrors = Observable<String>.create { observer inobserver.onNext("alan")observer.onNext("xing")observer.onNext("zhai")if count == 1 {// 流程進來之后就會過度-這里的條件可以作為出口,失敗的次數(shù)observer.onError(self.spError) // 接收到了錯誤序列,重試序列發(fā)生print("錯誤序列來了")count += 1}observer.onNext("liLie")observer.onNext("yanzi")observer.onNext("ting")observer.onCompleted()return Disposables.create()}sequenceRetryErrors.retry().subscribe(onNext: { print($0) }).disposed(by: disposeBag)/***輸出結(jié)果:*****retry*****alanxingzhai錯誤序列來了alanxingzhailiLieyanziting*/
5.4:retry(_:):
- 通過重新訂閱可觀察到的序列,重復(fù)地從錯誤事件中恢復(fù),直到重試次數(shù)達到max未遂計數(shù)
print("*****retry(_:)*****")var count = 1let sequenceThatErrors = Observable<String>.create { observer inobserver.onNext("alan")observer.onNext("xing")observer.onNext("qiangqiang")if count < 5 { // 這里設(shè)置的錯誤出口是沒有太多意義的額,因為我們設(shè)置重試次數(shù)observer.onError(self.spError)print("錯誤序列來了")count += 1}observer.onNext("liLei")observer.onNext("yanzi")observer.onNext("ting")observer.onCompleted()return Disposables.create()}sequenceThatErrors.retry(3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
2.6:Rx流程操作符。
2.6.1:debug
- 打印所有訂閱、事件和處理。
print("*****debug*****")var count = 1let sequenceThatErrors = Observable<String>.create { observer inobserver.onNext("alan")observer.onNext("zhai")observer.onNext("qiang")if count < 5 {observer.onError(self.spError)print("錯誤序列來了")count += 1}observer.onNext("liLei")observer.onNext("yanzi")observer.onNext("zhuang")observer.onCompleted()return Disposables.create()}sequenceThatErrors.retry(3).debug().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
2.7:鏈接操作符
2.7.1:multicast
- 將原可觀察序列轉(zhuǎn)換為可連接序列,并通過指定的主題廣播發(fā)射。
func testMulticastConnectOperators(){print("*****multicast*****")let netOB = Observable<Any>.create { (observer) -> Disposable insleep(2)// 模擬網(wǎng)絡(luò)延遲print("我開始請求網(wǎng)絡(luò)了")observer.onNext("請求到的網(wǎng)絡(luò)數(shù)據(jù)")observer.onNext("請求到的本地")observer.onCompleted()return Disposables.create {print("銷毀回調(diào)了")}}.publish()netOB.subscribe(onNext: { (anything) inprint("訂閱1:",anything)}).disposed(by: disposeBag)// 我們有時候不止一次網(wǎng)絡(luò)訂閱,因為有時候我們的數(shù)據(jù)可能用在不同的地方// 所以在訂閱一次 會出現(xiàn)什么問題?netOB.subscribe(onNext: { (anything) inprint("訂閱2:",anything)}).disposed(by: disposeBag)/**輸出結(jié)果為:*****multicast*****我開始請求網(wǎng)絡(luò)了訂閱1: 請求到的網(wǎng)絡(luò)數(shù)據(jù)訂閱2: 請求到的網(wǎng)絡(luò)數(shù)據(jù)訂閱1: 請求到的本地訂閱2: 請求到的本地銷毀回調(diào)了**/_ = netOB.connect()}
2.7.2:replay
- 將原可觀察序列轉(zhuǎn)換為可連接的序列,并將向每個新訂閱服務(wù)器重放以前排放的緩沖大小
- 首先擁有和publish一樣的能力,共享 Observable sequence, 其次使用replay還需要我們傳入一個參數(shù)(buffer size)來緩存已發(fā)送的事件,當(dāng)有新的訂閱者訂閱了,會把緩存的事件發(fā)送給新的訂閱者
print("*****replay*****")let intSequence = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).replay(5)_ = intSequence.subscribe(onNext: { print(Date(),"訂閱 1:, Event: \($0)") })DispatchQueue.main.asyncAfter(deadline: .now() + 2) {_ = intSequence.connect()}DispatchQueue.main.asyncAfter(deadline: .now() + 4) {_ = intSequence.subscribe(onNext: { print(Date(),"訂閱 2:, Event: \($0)") })}DispatchQueue.main.asyncAfter(deadline: .now() + 8) {_ = intSequence.subscribe(onNext: { print(Date(),"訂閱 3:, Event: \($0)") })}DispatchQueue.main.asyncAfter(deadline: .now() + 10) {self.disposeBag = DisposeBag()}
三:示例
3.1:簡單實用RxSwift 做一個計時器功能,控件綁定數(shù)據(jù)基礎(chǔ)用法
計時器源碼
文章Demo源碼