RxSwift學(xué)習(xí)之旅-初見RxSwift

概念性的東西就不在這里做過多的陳述了,在這里只說明兩點(diǎn):

RxSwift究竟是什么

RxSwift is a library for composing asynchronous and event-based code by using observable sequences and functional style operators, allowing for parameterized execution via schedulers.

RxSwift幫我們解決了什么問題

  1. State, and specifically, shared mutable state
  2. Imperative programming
  3. Side effects
  4. Declarative code
  5. Reactive systems

這里只是很簡(jiǎn)單的介紹了下RxSwift,別問為什么是英文,本人英語水平實(shí)在是不敢在這里班門弄斧,同時(shí)也避免翻譯的不準(zhǔn)確給你造成誤導(dǎo)。你可以在RxSwift的GitHub上找到更多關(guān)于它的詳細(xì)介紹

要使用RxSwift首先需要了解三樣?xùn)|西

Observables(被觀察者)

Observable<T>這個(gè)類提供了Rx的基礎(chǔ)代碼,它能夠產(chǎn)生一個(gè)異步的事件流去傳輸關(guān)于泛型T類型的相關(guān)數(shù)據(jù)。簡(jiǎn)單點(diǎn)說就是它能夠在當(dāng)前類訂閱(接收到)另外一個(gè)類發(fā)送數(shù)據(jù)
Observable<T>這個(gè)類也允許多個(gè)observers響應(yīng)事件去更新UI或者去處理接收到的數(shù)據(jù)
ObservableType這是Observable<T>遵守的一個(gè)協(xié)議,也就限制了一個(gè)Observable只能發(fā)出(或者一個(gè)observers只能接收)三種類型的事件

  • A next event: 這個(gè)事件攜帶最新的數(shù)據(jù),observers通過訂閱這個(gè)事件接收到最新的數(shù)據(jù)
  • A completed event: 這個(gè)事件表示一個(gè)事件序列的完結(jié),observers接收到這個(gè)事件后就再也接收不到其它任何事件
  • An error event: 一個(gè)事件序列因一個(gè)錯(cuò)誤而終止,observers接收到這個(gè)事件后就再也接收不到其它任何事件

Operators

類似于數(shù)學(xué)中的+ - * /,Rx也提供了一些方便我們對(duì)數(shù)據(jù)進(jìn)行處理的操作符

UIDevice.rx.orientation
  .filter { value in
    return value != .landscape
  }.map { _ in
    return "Portrait is the best!"
  }.subscribe(onNext: { string in
    showAlert(text: string)
  })

上面的例子中,每當(dāng)設(shè)備的方向發(fā)生改變,我們接收到事件,但是接收到的值并不是我們想要的最終結(jié)果,那我們就需要借助Rx中的操作符對(duì)數(shù)據(jù)進(jìn)行處理

Paste_Image.png
  1. 首先,filter只會(huì)允許.landscape通過值。如果設(shè)備在橫向模式,訂閱代碼不會(huì)執(zhí)行,因?yàn)閒ilter會(huì)抑制這些事件
  2. 在value = .portrait的情況下map接收到輸入,并把值轉(zhuǎn)換為一個(gè)字符串輸出的文本"Portrait is the best!"
  3. 最后你訂閱next事件,在value = .portrait的情況下將接收到已經(jīng)處理完成的文本"Portrait is the best!",你可以調(diào)用一個(gè)方法將這個(gè)文本直接顯示在屏幕上

Schedulers

Schedulers在Rx中等價(jià)于iOS當(dāng)中的dispatch queues,在Rx中已經(jīng)幫我們定義好了許多常用Schedulers,這些定義好的Schedulers可以幫助我們解決開發(fā)中的大部分問題

  • ConcurrentDispatchQueueScheduler可以并發(fā)執(zhí)行你的代碼
  • OperationQueueScheduler可以讓你在你給定的隊(duì)列上運(yùn)行你的事件序列

在學(xué)習(xí)Rx基礎(chǔ)階段并不會(huì)使用到它,這里只是簡(jiǎn)單的介紹,如果這系列文章能持續(xù)更新的話我打算后面再結(jié)合具體事例進(jìn)行更加詳細(xì)的講解

Getting started

了解完過后就可以學(xué)習(xí)一些Rx的基礎(chǔ)代碼了,首先創(chuàng)建一個(gè)工程,并使用CocoaPods將RxSwift集成到你的項(xiàng)目中,創(chuàng)建一個(gè)playground在你的項(xiàng)目中,以便更流暢的書寫Rx測(cè)試代碼,避免過多的command+R浪費(fèi)很多時(shí)間,完成后應(yīng)該是這樣的

Snip20170524_2.png

然后定義這樣一個(gè)方法,以便我們進(jìn)行更好的練習(xí)

public func example(of description: String, action: () -> Void) {
    print("\n--- Example of:", description, "---")
    action()
}
create

首先我們需要知道What is an observable?
常見的兩種方式來創(chuàng)建一個(gè)Observable對(duì)象,一種是通過引入RxCocoa(RxCocoa是對(duì)cocoa進(jìn)行的Rx擴(kuò)展),它已經(jīng)包含了我們常用到的Observable流,比如button的tap事件
let observable = loginButton.rx.tap.asObservable()
也可以使用提供的create函數(shù)來創(chuàng)建一個(gè)Observable對(duì)象

example(of: "create") {
    enum MyError: Error {
        case anError
    }
    
    Observable<String>.create({ (observer) -> Disposable in
        observer.onNext("1")
        observer.onNext("?")
        observer.onCompleted()
//        observer.onError(MyError.anError)
        return Disposables.create()
    }).subscribe({ (event) in
        print(event)
    }).disposed(by: DisposeBag())
}
//--- Example of: create ---
//next(1)
//next(?)
//completed

Disposing

到這里我們必須要知道dispose,在一個(gè)observable被訂閱前它不做任何事情,subscribe觸發(fā)observable發(fā)送事件直到observable發(fā)送.completed.error事件終止,如果我們的subscribe沒有收到.completed.error事件那誰來終止這次observable sequence呢?那就是DisposeBag。Rx官方建議我們每一個(gè)subscribe都應(yīng)該dispose,以免造成內(nèi)存泄漏

example(of: "DisposeBag") {
    let disposeBag = DisposeBag()
    Observable.of("A", "B", "C").subscribe({
        print($0)
    }).addDisposableTo(disposeBag) 
}
![Uploading Snip20170524_14_517335.png . . .]

上述事例當(dāng)disposeBag生命周期結(jié)束時(shí),即使subscribe沒有收到.completed.error事件,observable sequence也將會(huì)被終止

just
example(of: "What is an observable?") { 
    let one = 1
    let observable: Observable<Int> = Observable<Int>.just(one)
}
Snip20170524_3.png

上面的事例中我們通過Observable.just方法創(chuàng)建了只包含一個(gè)元素的observable sequence,我們可以通過訂閱它獲取到它發(fā)送的事件

subscribe
example(of: "What is an observablee?") { 
    let one = 1
    let observable: Observable<Int> = Observable<Int>.just(one)

    observable.subscribe({ (event) in
        print(event)
    })
}
//print:
//--- Example of: What is an observable? ---
//next(1)
//completed
Snip20170524_6.png

這個(gè)方法可以訂閱到observable發(fā)出的任何事件,在上面的例子中我們看到observable發(fā)出了兩個(gè)事件next(1)completed
還有一個(gè)跟它很像的訂閱方法,也是我們開發(fā)中經(jīng)常用到的訂閱方法

Snip20170524_12.png

一目了然,對(duì)應(yīng)的事件在對(duì)應(yīng)的閉包當(dāng)中響應(yīng),需要注意的是這里的參數(shù)就不在是事件了,而是事件攜帶的具體的值。并且對(duì)于我們不關(guān)注的事件是可以省略的哦~

observable.subscribe(onNext: { (Int) in
        code
    }, onError: { (Error) in
        code
    }, onCompleted: { 
        code
    }, onDisposed: { 
        code
    })
of
example(of: "of") { 
    let one = 1
    let two = 2
    let three = 3
    let observable = Observable.of(one, two, three)
    
    observable.subscribe({ (event) in
        print(event)
    })
}
//print:
//--- Example of: of ---
//next(1)
//next(2)
//next(3)
//completed

Snip20170524_7.png

上面的事例中我們通過Observable.of方法創(chuàng)建了包含三個(gè)元素的observable squence,我們通過訂閱發(fā)現(xiàn)它使用三次next事件依次發(fā)送我們給它的三個(gè)值,然后發(fā)送completed事件告訴我們這個(gè)observable的生命周期結(jié)束,不會(huì)再發(fā)送新的值。如果我們將三個(gè)值包成一個(gè)數(shù)組會(huì)發(fā)生什么呢?

example(of: "of") {
    let one = 1
    let two = 2
    let three = 3
    let observable = Observable.of([one, two, three])
    
    observable.subscribe({ (event) in
        print(event)
    })
}
//print:
//--- Example of: of ---
//next([1, 2, 3])
//completed

他會(huì)將這個(gè)數(shù)組用一個(gè)next事件發(fā)送給我們,那如果我們開發(fā)中需要給他一個(gè)數(shù)組,讓他依次發(fā)送給我們應(yīng)該怎么辦呢?

from
example(of: "from") {
    let one = 1
    let two = 2
    let three = 3
    let observable = Observable.from([one, two, three])
    
    observable.subscribe({ (event) in
        print(event)
    })
}
//print:
//--- Example of: from ---
//next(1)
//next(2)
//next(3)
//completed
Snip20170524_8.png

改用from就搞定了,創(chuàng)建observable sequence的方法還有很多,直接上代碼吧

empty
example(of: "empty") { //只能收到completed
    let observable = Observable<Void>.empty()
    observable.subscribe({ (event) in
        print(event)
    })
}
//print:
//--- Example of: empty ---
//completed
Snip20170524_9.png
never
example(of: "never") { //不發(fā)送任何事件
    let observable = Observable<Any>.never()
    observable.subscribe({ (event) in
        print(event)
    })
}
//print:
Snip20170524_10.png
range
example(of: "range") { 
    let observable = Observable<Int>.range(start: 1, count: 10)
    observable.subscribe(onNext: { (i) in
        print(i)
    })
}
//print:
//--- Example of: range ---
//    1
//    2
//    3
//    4
//    5
//    6
//    7
//    8
//    9
//    10
Snip20170524_11.png
deferred
example(of: "deferred") { 
    let disposeBag = DisposeBag()
    var flip = false
    
    let factory:Observable<Int> = Observable.deferred({ () -> Observable<Int> in
        flip = !flip
        if flip {
            return Observable.of(1,2,3)
        } else {
            return Observable.of(4,5,6)
        }
    })
    for _ in 0...3 {
        factory.subscribe(onNext: {
            print($0, terminator: "")
        }).addDisposableTo(disposeBag)
        print()
    }
}
// --- Example of: deferred ---
//    123
//    456
//    123
//    456

Snip20170524_14.png

Subject

Subject就相當(dāng)于一個(gè)橋梁或者代理,它既可以作為一個(gè)observer也可以作為一個(gè)Observable

下面來看幾種不同的Subject:

PublishSubject

PublishSubject只會(huì)發(fā)送給訂閱者訂閱之后的事件,之前發(fā)生的事件將不會(huì)發(fā)送。

example(of: "PublishSubject") {
    let subject = PublishSubject<String>()
    subject.onNext("Is anyone listening?")
    let subscriptionOne = subject.subscribe(onNext: { string in
            print(string)
        })
    subject.on(.next("1"))
    subject.onNext("2")
    
    let subscriptionTwo = subject
        .subscribe { event in
            print("2)", event.element ?? event)
    }
    subject.onNext("3")
    subscriptionOne.dispose()
    subject.onNext("4")
    
    // 1
    subject.onCompleted()
    // 2
    subject.onNext("5")
    // 3
    subscriptionTwo.dispose()
    let disposeBag = DisposeBag()
    // 4
    subject.subscribe {
            print("3)", $0.element ?? $0)
    }.addDisposableTo(disposeBag)
    subject.onNext("?")
}
//--- Example of: PublishSubject ---
//1
//2
//3
//2) 3
//2) 4
//2) completed
//3) completed

如果要保證所有事件都能被訂閱到,可以使用Create主動(dòng)創(chuàng)建或使用ReplaySubject。
如果被觀察者因?yàn)殄e(cuò)誤被終止,PublishSubject只會(huì)發(fā)出一個(gè)錯(cuò)誤的通知。

ReplaySubject

不管訂閱者什么時(shí)候訂閱的都可以把所有發(fā)生過的事件發(fā)送給訂閱者。

example(of: "ReplaySubject") {
    // 1
    let subject = ReplaySubject<String>.create(bufferSize: 2) //bufferSize指定緩沖區(qū)的大小
    let disposeBag = DisposeBag()
    // 2
    subject.onNext("1")
    subject.onNext("2")
    subject.onNext("3")
    // 3
    subject
        .subscribe {
            print(label: "1)", event: $0)
        }
        .addDisposableTo(disposeBag)
    subject
        .subscribe {
            print(label: "2)", event: $0)
        }
        .addDisposableTo(disposeBag)
    
    subject.onNext("4")
    subject.onError(MyError.anError)
    subject.dispose()

    subject
        .subscribe {
            print(label: "3)", event: $0)
    }
        .addDisposableTo(disposeBag)
    
}
//        --- Example of: ReplaySubject ---
//    1) 2
//    1) 3
//    2) 2
//    2) 3
//    1) 4
//    2) 4
//    1) anError
//    2) anError
//    3) Object `RxSwift.ReplayMany<Swift.String>` was already disposed.

BehaviorSubject

廣播所有事件給訂閱者,對(duì)于新的訂閱者,廣播最近的一個(gè)事件或者默認(rèn)值

// 1
enum MyError: Error {
    case anError
}
// 2
func print<T: CustomStringConvertible>(label: String, event: Event<T>) {
    print(label, event.element ?? event.error ?? event)
}
// 3
example(of: "BehaviorSubject") {
    // 4
    let subject = BehaviorSubject(value: "Initial value")
    let disposeBag = DisposeBag()
    
    subject.subscribe {
            print(label: "1)", event: $0)
        }.addDisposableTo(disposeBag)
    subject.onNext("X")
    // 1
    subject.onError(MyError.anError)
    // 2
    subject.subscribe {
            print(label: "2)", event: $0)
        }.addDisposableTo(disposeBag)
}
//        --- Example of: BehaviorSubject ---
//    1) Initial value
//    1) X
//    1) anError
//    2) anError

PublishSubject, ReplaySubject, and BehaviorSubject當(dāng)他們被回收時(shí),不會(huì)自動(dòng)發(fā)送完成事件

Variable

Variable是BehaviorSubject的封裝,它和BehaviorSubject不同之處在于,不能向Variable發(fā)送.Complete和.Error,它會(huì)在生命周期結(jié)束被釋放的時(shí)候自動(dòng)發(fā)送.Complete

example(of: "Variable") {
    // 1
    var variable = Variable("Initial value")
    let disposeBag = DisposeBag()
    // 2
    variable.value = "New initial value"
    // 3
    variable.asObservable()
        .subscribe {
            print(label: "1)", event: $0)
        }
        .addDisposableTo(disposeBag)
    // 1
    variable.value = "1"
    // 2
    variable.asObservable()
        .subscribe {
            print(label: "2)", event: $0)
        }
        .addDisposableTo(disposeBag)
    // 3
    variable.value = "2"
    
    // These will all generate errors
//    variable.value.onError(MyError.anError)
//    variable.asObservable().onError(MyError.anError)
//    variable.value = MyError.anError
//    variable.value.onCompleted()
//    variable.asObservable().onCompleted()
 
}
//    --- Example of: Variable ---
//1) New initial value
//1) 1
//2) 1
//1) 2
//2) 2

本文參考資料

RxSwift
RxSwift
alonemonkey

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容