秒极速赛车|秒极速赛车|75秒极速赛车|75秒赛车
官方
客服
訂閱號

RxSwift特征序列

hibo 2019-08-01 10:07:30 816

一到逼、概述

二漢采、Single

三嘯嫩釜、Completable

四瓣、Maybe

五頒示、Driver

六靖勺淚、Signal

七獵、ControlEvent

ReactiveX.png

一輝晴刊、概述

任何序列都可以用Observable描述店,創建序列 -> 訂閱序列 -> 信號發送 -> 信號接收恰閃。

Observable.create { (observer) -> Disposable inobserver.onNext("信號1")return Disposables.create()
}.subscribe(onNext: { (val) inprint("信號接收區希︰\(val)")
}).disposed(by: disposeBag)復制代碼

Observable是通用序列的描述符慣,調用.onNext獺海,.onError項太,onCompleted來發送信號匙騰,通用性強界,但針對特殊需求可能會覺得繁瑣紉慧,因此RxSwift還提供了一組特征序列礙俄,是Observable序列的變種垮桓,它能夠幫助我們更準確的描述序列講。即Single疆飛秤、Completable閨、Maybe餐攝、Driver莫霧箋、Signal掀蛔釁、ControlEvent贖腹哎。

二拭彌啪、Single

1劍、定義

單元素序列塑覆,信號只發送一次潰鬧,響應信號或錯誤信號咎冀。

Single.create { (single) -> Disposable insingle(.success("假裝我是一個正兒八經的數據"))
            //single(.error(NSError.init(domain: "網絡出現錯誤", code: 101, userInfo:["name":"hibo"])))return Disposables.create()
        }.subscribe(onSuccess: { (val) inprint("Single:\(val)")
        }) { (error) inprint("SingleError:\(error)")
        }.disposed(by: disposeBag)復制代碼
  • sinngle(.success(data))  -> onSuccess     發送響應元素到成功觀察者

  • sinngle(.error(error))  -> error    發送錯誤元素到錯誤觀察者

響應元素和錯誤元素分開處理淮,此時我們可以聯想到應用中的網絡請求薊陵降,成功數據用來渲染盯聊林,錯誤數則據彈出提示框儡融。

2罕難臘、源碼探索

2.1謾、Single定義

/// Sequence containing exactly 1 element
public enum SingleTrait { }
/// Represents a push style sequence containing 1 element.
public typealias Single= PrimitiveSequencepublic enum SingleEvent{
    /// One and only sequence element is produced. (underlying observable sequence emits: `.next(Element)`, `.completed`)case success(Element)
    
    /// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`)case error(Swift.Error)
}復制代碼

定位到Single.swift文件晶妨嗅,首先能看到SinglePrimitiveSequence結構體類型的別名降童貧,SingleEvent是事件枚舉揩,有successerror兩個成員變量懈娥如。

2.2墮梅、create創建序列踢捆。代碼如下(此處代碼標記為1??)疆︰

extension PrimitiveSequenceType where TraitType == SingleTrait {
    public typealias SingleObserver = (SingleEvent) -> Void
          //代碼省略若干行
    public static func create(subscribe: @escaping (@escaping SingleObserver) -> Disposable) -> Single{let source = Observable.create { observer inreturn subscribe { event inswitch event {case .success(let element):
                    observer.on(.next(element))
                    observer.on(.completed)case .error(let error):
                    observer.on(.error(error))
                }
            }
        }        return PrimitiveSequence(raw: source)
    }
}復制代碼

首先看參數是一個帶Disposable類型返回值的閉包習媒蔥,交由外部(業務層)實現鞭露,內部調用向外傳入一個SingleObserver閉包踏豪毖,以上寫法不太好理解兢餞,我們可以換一種寫法騷含︰

public static func create(subscribe: @escaping (@escaping SingleObserver) -> Disposable) -> Single{let source = Observable.create { observer in// 1確、內部實現一個閉包古,用來接收外界傳入的SingleEvent信號口詭將,接著做進一步的信號發送let block = { (event:SingleEvent) -> Void inswitch event {case .success(let element):
                observer.on(.next(element))
                observer.on(.completed)case .error(let error):
                observer.on(.error(error))
            }
        }
        // 2茨算、調用外部實現的閉包方法特貌囪,向外部發送內部實現的閉包方法做連接作用let disposable = subscribe(block)//3猴、返回值Disposable對象 return disposable
    }return PrimitiveSequence(raw: source)//4尉、創建PrimitiveSequence對象並保存Observable序列對象
}復制代碼
  • 內部實現一個閉包block祿秀瑯,用來接收外界傳入的SingleEvent信號塊隻,接著做進一步的信號發送

  • 調用外部實現的閉包方法軌,將內部實現的閉包block發送出去滔,起連接作用

  • 創建PrimitiveSequence對象並保存Observable序列對象source虛瞎適,返回PrimitiveSequence對象

create方法內部實際上實現了一個Observable序列此府單,由此可見Single序列是對Observable序列的封裝韌饋,Disposable對象通過閉包交由業務層創建喘韭斯,Single序列在實現上磨珊,方式方法與Observable保持一致鞠,此處可稱一絕嫁戶。當前我們只探索Single的信號是如何完成傳遞期暴莢,Observable序列的信號傳遞流程在中有詳細介紹年駿。

2.3厘放、訂閱序列

也是在同PrimitiveSequenceType擴展中定義壽怖,代碼如下(此處代碼標記為2??)綽︰

public func subscribe(onSuccess: ((ElementType) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil) -> Disposable {#if DEBUG let callStack = Hooks.recordCallStackOnError ? Thread.callStackSymbols : []#elselet callStack = [String]()#endifreturn self.primitiveSequence.subscribe { event inswitch event {case .success(let element):
            onSuccess?(element)case .error(let error):if let onError = onError {
                onError(error)
            } else {
                Hooks.defaultErrorHandler(callStack, error)
            }
        }
    }
}復制代碼

方法中先調用了self.primitiveSequence方法惱縛,返回了self激泛測,方法是在遵循PrimitiveSequenceType協議的PrimitiveSequence的擴展中幻當,為了保證協議的一致性隊忍劇。代碼如下午紳︰

extension PrimitiveSequence: PrimitiveSequenceType {
    /// Additional constraints
    public typealias TraitType = Trait
    /// Sequence element typepublic typealias ElementType = Element

    // Converts `self` to primitive sequence.
    ///
    /// - returns: Observable sequence that represents `self`.
    public var primitiveSequence: PrimitiveSequence{return self
    }
}復制代碼

緊接著調用另一個subscribe方法德餒,代碼如下(此處代碼標記為3??)簾︰

public func subscribe(_ observer: @escaping (SingleEvent) -> Void) -> Disposable {
    var stopped = falsereturn self.primitiveSequence.asObservable().subscribe { event inif stopped { return }
        stopped = true
        switch event {case .next(let element):
            observer(.success(element))case .error(let error):
            observer(.error(error))case .completed:
            rxFatalErrorInDebug("Singles can't emit a completion event")
        }
    }
}復制代碼
  • self.primitiveSequence -> asObservable() -> subscribe

  • 此處截斷了completed信號的向上傳遞跺奈,因此Single序列只能收到響應信號和錯誤信號

該段代碼也調用了self.primitiveSequence方法督,接著調用asObservable()方法問,查看代碼發現此處是為了獲取source對象績,即Observable可觀察序列齲勿仍。

再查看subscribe的方法(此處標記為代碼4??)殘︰

public func subscribe(_ on: @escaping (Event) -> Void)
    -> Disposable {let observer = AnonymousObserver { e inon(e)
        }return self.asObservable().subscribe(observer)
}復制代碼
  • 代碼創建了一個觀75秒极速赛车察者瞪熱富,當前觀察者將會收到發送過來的消息諱卷 ,並由此通過閉包一層層傳到業務層顯。 4?? -> 3?? -> 2?? -> 1?? ->業務層

  • 當前self指向的是1??處創建並保存的Observable類型的source對象龔,因此該處subscribe所調用的即是Produce類中的subscribe方法醚,在方法內部創建了sink對象婆效,來觸發創建序列時實現的閉包締,即代碼1??處所create後的閉包

  • 此時就到了業務層田蝗癌,通過create內部實現的閉包single向內部發送消息誨逞,再有observer調用on來向觀察者發送信號

  • 信號發送不做贅述先籃山,最終會到達4??處代碼的觀察者睡刻白,此時再由閉包一層層向上傳遞投填,直到業務層的監听閉包

總結九皖︰

序列的產生肋粱,訂閱簇含,發送烙,接收還是由Observable來實現的速,Single只是對Observable做了封裝綱毖碩,去除了onCompleted的消息監听及消息發送借蛋。

具體的Observable序列產生到觀察流程見

三苯傷、Completable

只能產生completed事件和error事件坍,沒有序列元素值產生溫記。

Completable.create { (completable) -> Disposable incompletable(.completed)
    //completable(.error(NSError.init(domain: "出現異常", code: 101, userInfo: nil)))return Disposables.create()
}.subscribe(onCompleted: {print("Completable")
}) { (error) inprint(error)
}.disposed(by: disposeBag)復制代碼
  • 應用場景祭,只關心任務是否完成草,不關心不需要結果

  • Competable.swift下匠,在PrimitiveSequenceType擴展中實現了序列的創建盒,訂閱 快拎,即信號轉發

定義如下類堿啼︰

/// Sequence containing 0 elements
public enum CompletableTrait { }
/// Represents a push style sequence containing 0 elements.
public typealias Completable = PrimitiveSequencepublic enum CompletableEvent {
    /// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`)case error(Swift.Error)
    
    /// Sequence completed successfully.case completed
}復制代碼

同樣Completable類也是PrimitiveSequence的別名筒攝,並聲明一個枚舉包含憤,errorcompleted成員變量糠話,限定了事件產生類型眷阿。都是對Observable序列的封裝從媳,源碼此處不做探索說明此糠,和Single一致碑念,只是在訂閱階段對.next事件做了攔截錠杏婚。

四差褂集、Maybe

Single序列相似竅毆,發出一個元素或一個completed事件或error事件埔。

Maybe.create { (maybe) -> Disposable inmaybe(.success("element"))
        //maybe(.completed)
        //maybe(.error(NSError.init(domain: "出現異常", code: 101, userInfo: nil)))return Disposables.create()
    }.subscribe(onSuccess: { (val) inprint(val)
    }, onError: { (error) inprint("error:\(error)")
    }) {print("completed")
    }.disposed(by: disposeBag)復制代碼

在開發中妒盟,如果一個業務有時候需要一個元素冬薄魯,有時候只需要知道處理完成的時候山辣窖,可以使用該Maybe盼愧瓜,解決不確定需求問題媽。源碼探索略瞳,同上泵。

五芯、Driver

老司機開車永遠不會出錯莢撤,因此Driver序列不會產生error事件托,並一定在主線程中監听母欣,會想新訂閱者發送骨癌,上次發送出的元素斗,主要為簡化UI層的代碼昂苫平。下面看看為什麼會有Driver序列恆凳。

有一個需求口錢降︰

  • 搜索框中每次輸入一個文本背黑,獲取一次網絡請求掂弗酚,成功後渲染UI

先實現一個簡單的UI燙酒肌︰

let tf = UITextField.init(frame: CGRect(x: 100, y: 100, width: 200, height: 40))
tf.borderStyle = .roundedRect
tf.placeholder = "請輸入"self.view.addSubview(tf)let label1 = UILabel.init(frame: CGRect(x: 100, y: 160, width: 200, height: 40))
label1.backgroundColor = .groupTableViewBackground
label1.textAlignment = .center
self.view.addSubview(label1)let label2 = UILabel.init(frame: CGRect(x: 100, y: 210, width: 200, height: 40))
label2.backgroundColor = .groupTableViewBackground
label2.textAlignment = .center
self.view.addSubview(label2)復制代碼

創建了一個textfield男萄稼,兩個label用來展示吳墓裸。下面在來實現一個網絡請求廊擠,返回一個Single序列欠︰

func network(text:String) -> Single{return Single.create(subscribe: { (single) -> Disposable inif text == "1234"{
            single(.error(NSError.init(domain: "出現錯誤", code: 101, userInfo: nil)))
        }
        DispatchQueue.global().async {print("請求網絡")
            single(.success(text))
        }return Disposables.create()
    })
}復制代碼

網絡請求為耗時操作興,因此我們在異步中來完成唐,直接發送序列紉盾容,假裝我們請求了一次網絡尼希蒙。

再實現textfield輸入序列的監听商沫科,並調取網絡請求方法顴︰

let result = tf.rx.text.orEmpty.skip(1)
                .flatMap{return self.network(text: $0)
                        .observeOn(MainScheduler.instance)
                        .catchErrorJustReturn("網絡請求失敗")
            }.share(replay: 1, scope: .whileConnected)
//網絡請求將發送多次請求
result.subscribe(onNext: { (val) inprint("訂閱一屎乳︰\(val) 線程壘申︰\(Thread.current)")
}).disposed(by: disposeBag)

result.subscribe(onNext: { (val) inprint("訂閱二如︰\(val) 線程餐呻︰\(Thread.current)")
}).disposed(by: disposeBag)

result.map{"\(($0 as! String).count)"}.bind(to: label1.rx.text).disposed(by: disposeBag)
result.map{"\($0)"}.bind(to: label2.rx.text).disposed(by: disposeBag)復制代碼

代碼介紹

  • flatMap

  • observeOn選擇在哪個線程執行

  • catchErrorJustReturn錯誤處理稜瘸,將onError事件轉為onNext事件

  • share為多個觀察者共享資源方,網絡請求只發送呢一次淮,否則多個訂閱將會觸發多個請求

Driver實現訂礙肥︰

let result = tf.rx.text.orEmpty
    .asDriver()
    .flatMap {return self.network(text: $0).asDriver(onErrorJustReturn: "網絡請求失敗")
    }
result.map{"長度覓肉傅︰\(($0 as! String).count)"}
        .drive(label1.rx.text).disposed(by: disposeBag)
result.map{"\($0)"}.drive(label2.rx.text).disposed(by: disposeBag)復制代碼
  • asDriver()將序列轉換為Driver序列

  • map重新組合並生成新的序列

  • driver將元素在主線程中綁定到label1label2

相比非driver下的代碼實現徊暗潮,Driver序列省去了線程的設置常,share數據共享設置堿雇確。

源碼探索

斷點查看asDriver()方法力︰

extension ControlProperty {
    /// Converts `ControlProperty` to `Driver` trait.
    ///
    /// `ControlProperty` already can't fail, so no special case needs to be handled.
    public func asDriver() -> Driver{
        return self.asDriver { _ -> Driverin
            #if DEBUG
                rxFatalError("Somehow driver received error from a source that shouldn't fail.")
            #else
                return Driver.empty()
            #endif
        }
    }
}復制代碼

ControlProperty的擴展方法穩,返回了一個Driver類敲甸,DriverSharedSequence的別名富訂,用來描述不同類型的序列領浚,最後又調用了asDriver方法漿覓,而該方法在ObservableConvertibleType的擴展中涉鉗腔,一直追蹤會發現很多類都是繼承自ObservableConvertibleType下是敦。

extension ObservableConvertibleType {
    public func asDriver(onErrorRecover: @escaping (_ error: Swift.Error) -> Driver) -> Driver{let source = self
            .asObservable()
            .observeOn(DriverSharingStrategy.scheduler)
            .catchError { error inonErrorRecover(error).asObservable()
            }return Driver(source)
    }
}復制代碼

如上代碼也設置了observerOn方法刃,來指定線程疙,繼續深入能夠發現DriverSharingStrategy.scheduler內部指定的就是主線程荷肆廓,印證了上面所說的Driver的執行是在主線程的撾朵脊。下面再看flatMap方法的實現實架景︰

public func flatMap(_ selector: @escaping (E) throws -> O)
    -> Observable{return FlatMap(source: self.asObservable(), selector: selector)
}復制代碼

業務層實現閉包溫岸參,在閉包中調用了網絡請求方法霜儡,並向FlatMap中傳入業務層實現的閉包…… 當前篇幅過程糧,源碼分析需要另起篇幅喘埔霖。

六察刨槍、Signal

Driver相似跨蛙,不會產生error事件捶雄肺,在主線程執行卞,但不會像Driver一樣會給新觀察者發送上一次發送的元素系欺磺。

使用如下始肆︰

let event : Driver= button.rx.tap.asDriver()
event.drive(onNext: {print("yahibo")
    event.drive(onNext: {print("yahibo1")
    }).disposed(by: self.disposeBag)
}).disposed(by: disposeBag)復制代碼

運行打用久翰傘,發現在點擊後重新訂閱的觀察者蹋秀滔,會直接收到點擊事件巒屁鴕,這是我們業務不允許的攬任屢。下面再看Signal序列莎拐︰

let event : Signal= button.rx.tap.asSignal()
event.emit(onNext: {print("yahibo")
    event.emit(onNext: {print("yahibo1")
    }).disposed(by: self.disposeBag)
}).disposed(by: disposeBag)復制代碼

運行結果誹,每一個新序列都會在點擊後觸發鍍。

七悸、ControlEvent

專門用于描述UI控件所產生的事件貝,不會產生error事件皖磐,在主線程中監听禱吐椽。代碼如下輛槐︰

1氫、監听點擊事件

let event : ControlEvent= button.rx.tap.asControlEvent()
event.bind(onNext: {print("controllerEvent")
}).disposed(by: disposeBag)復制代碼

2惺、監听點擊事件並綁定數據到其他UI

let event : ControlEvent= button.rx.tap.asControlEvent()
event.map{"yahibo"}.bind(to: label1.rx.text).disposed(by: disposeBag)復制代碼

總結案翻︰

以上序列都是基于Observable的凹,是對其更高層的封裝竄,針對不同應用場景設計校,簡化不同場景下序列的使用流程甕謎痘。

|75秒极速赛车开奖记录网站-the best光大乐园
澳洲快樂8 澳洲快樂8開獎 澳洲快樂8開獎結果 澳洲快樂8官方網站 澳洲快樂8官網 澳洲快樂8網站 澳洲快樂8計劃 澳洲快樂8 澳洲快樂8 澳洲時時彩 澳洲時時彩 澳洲時時彩開獎 澳洲時時彩開獎結果 澳洲時時彩官方網站 澳洲時時彩官網 澳洲時時彩網站 澳洲時時彩計劃 澳洲時時彩 澳洲pk10 澳洲pk10 澳洲pk10開獎 澳洲pk10開獎結果 澳洲pk10官方網站 澳洲pk10官網 澳洲pk10網站 澳洲pk10計劃 澳洲pk10 澳洲幸運5 澳洲幸運5開獎 澳洲幸運5開獎結果 澳洲幸運5官方網站 澳洲幸運5官網 澳洲幸運5網站 澳洲幸運5計劃 澳洲幸運5 澳洲幸運5 澳洲快三 澳洲快三開獎 澳洲快三開獎結果 澳洲快三官方網站 澳洲快三官網 澳洲快三網站