概述
Rx 通過(guò) Observable<Element>接口來(lái)表達(dá)計(jì)算型泛型抽象 (generic abstraction of computation) 的概念,而 RxSwift 是 Rx 的 Swift 版本。無(wú)疑,這個(gè)內(nèi)容非常龐大,所以我打算用真是代碼側(cè)面描述一下自己對(duì)使用的一些心得體會(huì)以一種稍微簡(jiǎn)單點(diǎn)的介紹方式來(lái)講解這個(gè)框架。
1.首先我們要了解幾個(gè)關(guān)鍵詞
(1)Variable
Variable表示一個(gè)可監(jiān)聽(tīng)的數(shù)據(jù)結(jié)構(gòu)。使用Variable,你可以監(jiān)聽(tīng)數(shù)據(jù)的變化,也可以把其他值綁定到它身上。
例子一
class VariableController: UIViewController {
@IBOutlet weak var label: UILabel!
var disposeBag = DisposeBag()
var timer:Timer?
var count = Variable(0)
override func viewDidLoad() {
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector:#selector(VariableController.updateValue) , userInfo: nil, repeats: true)
_ = count.asObservable().subscribe(onNext: { (num) in
self.label?.text = "VariableValue:\(num)"
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
}
func updateValue(){
count.value = count.value + 1
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
timer?.invalidate()
}
}
例子二
//我們?cè)趘iewmodel里面創(chuàng)建Variable的變量
var isValidLoading: Variable = Variable("")
self.isValidLoading.value = "show"
//在vc里面去監(jiān)聽(tīng)做操作
self.viewModel.isValidLoading.asObservable().subscribe(onNext: { (result) in
if result == "show"{
self.showLoading()
}else{
self.hideLoading()
}
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
//注意這里的subscribe后會(huì)的到next(),必須通過(guò)onNext去取到里面的值
(2)Observable
Observable表示可監(jiān)聽(tīng)或者可觀察,也就是說(shuō)RxSwift的核心思想是可監(jiān)聽(tīng)的序列。并且,Observable sequence可以接受異步信號(hào),也就是說(shuō),信號(hào)是可以異步給監(jiān)聽(tīng)者的
Observable分為兩種
(1)在有限的時(shí)間內(nèi)會(huì)自動(dòng)結(jié)束(Completed/Error),比如一個(gè)網(wǎng)絡(luò)請(qǐng)求當(dāng)作一個(gè)序列,當(dāng)網(wǎng)絡(luò)請(qǐng)求完成的時(shí)候,Observable自動(dòng)結(jié)束,資源會(huì)被釋放
(2)信號(hào)不會(huì)自己結(jié)束,最簡(jiǎn)單的比如一個(gè)Timer,每隔一段時(shí)間發(fā)送一個(gè)新的信號(hào)過(guò)來(lái),這時(shí)候需要手動(dòng)取消監(jiān)聽(tīng),來(lái)釋放相應(yīng)的資源,又比如一個(gè)label.rac_text是一個(gè)Obserable,通常需要這樣調(diào)用addDisposableTo(disposeBag)來(lái)讓其在deinit,也就是所有者要釋放的時(shí)候,自動(dòng)取消監(jiān)聽(tīng)。
信號(hào)處理的順序
Observable有個(gè)隱式的約定,那就是在一個(gè)信號(hào)處理完成之前,不會(huì)發(fā)送下一個(gè)信號(hào),不管發(fā)送信號(hào)的線程是并發(fā)的or串行的。
someObservable
.subscribe { (e: Event<Element>) in
print("Event processing started")
// processing
print("Event processing ended")
}
//只會(huì)出現(xiàn)
Event processing started
Event processing ended
Event processing started
Event processing ended
Event processing started
Event processing ended
//不會(huì)出現(xiàn)
Event processing started
Event processing started
Event processing ended
Event processing ended
實(shí)例
//我們監(jiān)聽(tīng)textfield的文字變化,然后,Log出text,當(dāng)button點(diǎn)擊的時(shí)候,取消這次監(jiān)聽(tīng)
class ObservableAndCancelController : UIViewController{
var subscription:Disposable?
@IBOutlet weak var textfield: UITextField!
@IBAction func cancelObserve(sender: AnyObject) {
subscription?.dispose()
}
override func viewDidLoad() {
super.viewDidLoad()
subscription = textfield.rx.text.asObservable().subscribe(onNext: { (text) in
print(text)
})
}
}
map: 對(duì)信號(hào)(Element)進(jìn)行映射處理。比如輸入是String,影射到Bool
filter: 對(duì)信號(hào)(Element)進(jìn)行過(guò)濾處理。返回信號(hào),和輸入的信號(hào)是同一種類(lèi)型
combineLatest: 對(duì)兩種信號(hào)的值進(jìn)行結(jié)合??梢苑祷夭煌N類(lèi)的信號(hào)。
let firstObserverable = firstTextfield.rx.text.map({"first" + $0})
let secondObserverable = secondTextfield.rx.text.filter({$0.characters.count > 3})
_ = Observable.combineLatest(firstObserverable, secondObserverable, resultSelector:{ ($0 + $1,$0.characters.count + $1.characters.count)}).subscribe(onNext: { (element) in
print("combineLatest:\(element)")
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
//打印
combineLatest:("first1234abcd", 13)
combineLatest:("first1234abcde", 14)
combineLatest:("first1234abcdef", 15)
combineLatest:("first1234abcdefg", 16)
Observerable可以用來(lái)處理任務(wù),并且異步返回Event信號(hào)(Next,Error,Completion)
//Observable就是處理輸入,并且把description發(fā)送出去
func createObserveable(object:AnyObject?)->Observable<String?>{
return Observable.create({ observer in
observer.onNext(object?.description)
observer.onCompleted()
return NopDisposable.instance
})
}
_ = createObserveable(test).subscribe({ (event) in
switch event{
case .Next(let value):
print(value)
case .Completed:
print("Completed")
case .Error(let error):
print(error)
}
})
創(chuàng)建一個(gè)Observable相當(dāng)容易,調(diào)用Observable.create,在必要的時(shí)候發(fā)送onNext,onError,onCompleted信號(hào)。然后返回一個(gè)Disposable用來(lái)取消信號(hào)
(3)bindTo
數(shù)據(jù)綁定是開(kāi)發(fā)的時(shí)候很常見(jiàn)的,比如根據(jù)文本的輸入動(dòng)態(tài)調(diào)整textfield的背景色,動(dòng)態(tài)調(diào)整按鈕的enable。亦或者根據(jù)textfield的輸入變化,動(dòng)態(tài)的去反饋到model層。如果你聽(tīng)過(guò)MVVM,那你肯定知道,MVVM的難點(diǎn)就是ViewModel與View的數(shù)據(jù)綁定問(wèn)題。
//我們?cè)趘iewmodel里面創(chuàng)建Observable的變量
var isValidSendButton: Observable<Bool>!
//在vc里面去和按鈕的是否點(diǎn)擊進(jìn)行綁定
var disposeBag = DisposeBag()
self.viewModel.isValidSendButton.asObservable().bindTo(self.sendBtn!.rx.isEnabled).addDisposableTo(self.disposeBag)
講到這里我們已經(jīng)可以簡(jiǎn)單的來(lái)嘗試做一下事情了
class ObservableAndCancelController : UIViewController{
//userName 用來(lái)監(jiān)聽(tīng)輸入框的值
//password 用來(lái)監(jiān)聽(tīng)輸入框的值
var disposeBag = DisposeBag()
//這里的UITextField和UIButton的布局就根據(jù)自己的想法實(shí)例化,這里沒(méi)有寫(xiě),所以直接運(yùn)行是沒(méi)有效果的
var nameTextfield:UITextField?
var passwordTextfield:UITextField?
var registerButton:UIButton?
var userName:Variable = Variable("")
var password:Variable = Variable("")
var validUserName:Observable<Bool>!
var validPassword:Observable<Bool>!
var isValidSendButton: Observable<Bool>!
override func viewDidLoad() {
super.viewDidLoad()
self.nameTextfield?.rx.text.asObservable().subscribe(onNext:{ [weak self](result) in
self?.userName.value = result!
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
self.passwordTextfield?.rx.text.asObservable().subscribe(onNext:{ [weak self](result) in
self?.password.value = result!
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
validUserName = userName.asObservable().map({$0.characters.count >= 6}).shareReplay(1)
validPassword = password.asObservable().map({$0.characters.count >= 8}).shareReplay(1)
_ = validUserName.subscribe(onNext: { (valid) in
self.nameTextfield?.backgroundColor = valid ? UIColor.clear:UIColor.lightGray
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
_ = validPassword.subscribe(onNext: { (valid) in
self.passwordTextfield?.backgroundColor = valid ? UIColor.clear:UIColor.lightGray
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)//addDisposableTo(disposeBag)是為了自動(dòng)釋放
isValidSendButton = Observable.combineLatest(validUserName, validPassword) {$0 && $1}
isValidSendButton?.subscribe(onNext: {(result:Bool) in
if result{
self.registerButton?.isEnabled = true
self.registerButton?.backgroundColor = UIColor.red
}else{
self.registerButton?.isEnabled = false
self.registerButton?.backgroundColor = UIColor.darkGray
}
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
self.isValidSendButton.asObservable().bindTo(self.registerButton!.rx.isEnabled).addDisposableTo(self.disposeBag)
self.registerButton?.rx.tap.shareReplay(1).subscribe(onNext: { (result) in
print("Button tapped")
}, onError: nil, onCompleted: nil, onDisposed: nil).addDisposableTo(self.disposeBag)
}
}
以上是在網(wǎng)上的一些學(xué)習(xí)體會(huì)和自己的實(shí)戰(zhàn)總結(jié),講的不多,直講到一些基礎(chǔ)的使用方法,希望對(duì)入門(mén)的同學(xué)有些幫助,謝謝