概念性的東西就不在這里做過多的陳述了,在這里只說明兩點:
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幫我們解決了什么問題
- State, and specifically, shared mutable state
- Imperative programming
- Side effects
- Declarative code
- Reactive systems
這里只是很簡單的介紹了下RxSwift勾拉,別問為什么是英文捷凄,本人英語水平實在是不敢在這里班門弄斧,同時也避免翻譯的不準(zhǔn)確給你造成誤導(dǎo)浑玛。你可以在RxSwift的GitHub上找到更多關(guān)于它的詳細(xì)介紹
要使用RxSwift首先需要了解三樣?xùn)|西
Observables(被觀察者)
Observable<T>這個類提供了Rx的基礎(chǔ)代碼憎亚,它能夠產(chǎn)生一個異步的事件流去傳輸關(guān)于泛型T類型的相關(guān)數(shù)據(jù)衙耕。簡單點說就是它能夠在當(dāng)前類訂閱(接收到)另外一個類發(fā)送數(shù)據(jù)
Observable<T>這個類也允許多個observers響應(yīng)事件去更新UI或者去處理接收到的數(shù)據(jù)
ObservableType這是Observable<T>遵守的一個協(xié)議刃泌,也就限制了一個Observable只能發(fā)出(或者一個observers只能接收)三種類型的事件
- A next event: 這個事件攜帶最新的數(shù)據(jù)凡壤,observers通過訂閱這個事件接收到最新的數(shù)據(jù)
- A completed event: 這個事件表示一個事件序列的完結(jié),observers接收到這個事件后就再也接收不到其它任何事件
- An error event: 一個事件序列因一個錯誤而終止耙替,observers接收到這個事件后就再也接收不到其它任何事件
Operators
類似于數(shù)學(xué)中的+ - * /亚侠,Rx也提供了一些方便我們對數(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中的操作符對數(shù)據(jù)進(jìn)行處理
- 首先,filter只會允許.landscape通過值狐援。如果設(shè)備在橫向模式,訂閱代碼不會執(zhí)行,因為filter會抑制這些事件
- 在value = .portrait的情況下map接收到輸入钢坦,并把值轉(zhuǎn)換為一個字符串輸出的文本"Portrait is the best!"
- 最后你訂閱next事件究孕,在value = .portrait的情況下將接收到已經(jīng)處理完成的文本"Portrait is the best!"啥酱,你可以調(diào)用一個方法將這個文本直接顯示在屏幕上
Schedulers
Schedulers在Rx中等價于iOS當(dāng)中的dispatch queues爹凹,在Rx中已經(jīng)幫我們定義好了許多常用Schedulers,這些定義好的Schedulers可以幫助我們解決開發(fā)中的大部分問題
- ConcurrentDispatchQueueScheduler可以并發(fā)執(zhí)行你的代碼
- OperationQueueScheduler可以讓你在你給定的隊列上運行你的事件序列
在學(xué)習(xí)Rx基礎(chǔ)階段并不會使用到它镶殷,這里只是簡單的介紹禾酱,如果這系列文章能持續(xù)更新的話我打算后面再結(jié)合具體事例進(jìn)行更加詳細(xì)的講解
Getting started
了解完過后就可以學(xué)習(xí)一些Rx的基礎(chǔ)代碼了,首先創(chuàng)建一個工程绘趋,并使用CocoaPods將RxSwift集成到你的項目中颤陶,創(chuàng)建一個playground在你的項目中,以便更流暢的書寫Rx測試代碼陷遮,避免過多的command+R浪費很多時間滓走,完成后應(yīng)該是這樣的
然后定義這樣一個方法,以便我們進(jìn)行更好的練習(xí)
public func example(of description: String, action: () -> Void) {
print("\n--- Example of:", description, "---")
action()
}
create
首先我們需要知道What is an observable?
常見的兩種方式來創(chuàng)建一個Observable對象帽馋,一種是通過引入RxCocoa(RxCocoa是對cocoa進(jìn)行的Rx擴(kuò)展)搅方,它已經(jīng)包含了我們常用到的Observable流,比如button的tap事件
let observable = loginButton.rx.tap.asObservable()
也可以使用提供的create函數(shù)來創(chuàng)建一個Observable對象
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绽族,在一個observable被訂閱前它不做任何事情姨涡,subscribe觸發(fā)observable發(fā)送事件直到observable發(fā)送.completed或.error事件終止,如果我們的subscribe沒有收到.completed或.error事件那誰來終止這次observable sequence呢吧慢?那就是DisposeBag涛漂。Rx官方建議我們每一個subscribe都應(yīng)該dispose,以免造成內(nèi)存泄漏
example(of: "DisposeBag") {
let disposeBag = DisposeBag()
Observable.of("A", "B", "C").subscribe({
print($0)
}).addDisposableTo(disposeBag)
}
上述事例當(dāng)disposeBag生命周期結(jié)束時检诗,即使subscribe沒有收到.completed或.error事件匈仗,observable sequence也將會被終止
just
example(of: "What is an observable?") {
let one = 1
let observable: Observable<Int> = Observable<Int>.just(one)
}
上面的事例中我們通過Observable.just方法創(chuàng)建了只包含一個元素的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
這個方法可以訂閱到observable發(fā)出的任何事件逢慌,在上面的例子中我們看到observable發(fā)出了兩個事件next(1) 和 completed
還有一個跟它很像的訂閱方法悠轩,也是我們開發(fā)中經(jīng)常用到的訂閱方法
一目了然,對應(yīng)的事件在對應(yīng)的閉包當(dāng)中響應(yīng)涕癣,需要注意的是這里的參數(shù)就不在是事件了哗蜈,而是事件攜帶的具體的值。并且對于我們不關(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
上面的事例中我們通過Observable.of方法創(chuàng)建了包含三個元素的observable squence坠韩,我們通過訂閱發(fā)現(xiàn)它使用三次next事件依次發(fā)送我們給它的三個值距潘,然后發(fā)送completed事件告訴我們這個observable的生命周期結(jié)束,不會再發(fā)送新的值只搁。如果我們將三個值包成一個數(shù)組會發(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
他會將這個數(shù)組用一個next事件發(fā)送給我們,那如果我們開發(fā)中需要給他一個數(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
改用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
never
example(of: "never") { //不發(fā)送任何事件
let observable = Observable<Any>.never()
observable.subscribe({ (event) in
print(event)
})
}
//print:
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
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
Subject
Subject
就相當(dāng)于一個橋梁或者代理骚亿,它既可以作為一個observer
也可以作為一個Observable
已亥。
下面來看幾種不同的Subject
:
PublishSubject
PublishSubject只會發(fā)送給訂閱者訂閱之后的事件,之前發(fā)生的事件將不會發(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主動創(chuàng)建或使用ReplaySubject。
如果被觀察者因為錯誤被終止俱笛,PublishSubject只會發(fā)出一個錯誤的通知捆姜。
ReplaySubject
不管訂閱者什么時候訂閱的都可以把所有發(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
廣播所有事件給訂閱者迎膜,對于新的訂閱者泥技,廣播最近的一個事件或者默認(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)他們被回收時,不會自動發(fā)送完成事件
Variable
Variable是BehaviorSubject的封裝磕仅,它和BehaviorSubject不同之處在于珊豹,不能向Variable發(fā)送.Complete和.Error,它會在生命周期結(jié)束被釋放的時候自動發(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