最近有幸學(xué)習(xí)了一下RxSwift框架,突然有了一種發(fā)現(xiàn)新大陸的感覺,雖然之前也一直在用OC的RAC框架,但是在Swift開發(fā)中RxSwift真的是iOS開發(fā)者的利器,后悔沒有早點(diǎn)接觸,特此記錄一下。
官網(wǎng)地址
1、RxSwift導(dǎo)入
話不多說,直接上實(shí)操:
使用pods直接install最新的庫,cocoapods安裝就不說了,參考:cocoapods詳解
target 'YOUR_TARGET_NAME' do
pod 'RxSwift', '6.5.0'
pod 'RxCocoa', '6.5.0'
end
2、RxSwift簡單使用
import RxSwift
import RxCocoa
KVO使用
正常操作需要三步,1、添加觀察者對象 2、實(shí)現(xiàn)監(jiān)聽方法 3、銷毀觀察者
// 添加觀察者對象
func setupKVO() {
self.person.addObserver(self, forKeyPath: "name", options: .new, context: nil)
}
// 實(shí)現(xiàn)監(jiān)聽方法
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("響應(yīng)")
print(change as Any)
}
// 銷毀觀察者
deinit {
self.removeObserver(self.person, forKeyPath: "name", context: nil)
}
相對來說,用rxSwift實(shí)現(xiàn),一步到位,代碼簡潔,模塊功能劃分清晰,不用這邊寫一個那邊寫一個,增加代碼可讀性和可維護(hù)性
func setupKVO() {
self.person.rx.observeWeakly(String.self, "name")
.subscribe { value in
print(value as Any)
}
.disposed(by: disposeBag)
}
UIButton使用
UIButton我們平時(shí)使用也是一樣,點(diǎn)擊事件需要addTarget,然后在某一個地方,實(shí)現(xiàn)點(diǎn)擊事件函數(shù);
同樣的,用RxSwift也是一目了然。
// self.button.addTarget(self, action: #selector(<#T##@objc method#>), for: .touchUpInside)
self.button.rx.controlEvent(.touchUpInside)
.subscribe { _ in
print("點(diǎn)擊事件")
}
.disposed(by: disposeBag)
UITextField
func setupTextFiled() {
self.textFiled.rx.text.orEmpty.changed
.subscribe { text in
print(text)
}
.disposed(by: disposeBag)
}
同時(shí)textFiled也可以跟button進(jìn)行雙向綁定,輸入文字同步修改按鈕的值,也可以根據(jù)輸入文字長度,動態(tài)變更按鈕狀態(tài);
這個bind確實(shí)很好用,讓我想起之前做前端開發(fā)的時(shí)候,用的vue框架,v-bind,v-on,無需關(guān)心邏輯代碼,專心寫好業(yè)務(wù)代碼就好,簡直不要太爽
self.textFiled.rx.text
.bind(to: self.button.rx.title())
.disposed(by: disposeBag)
// 根據(jù)輸入文字長度,動態(tài)變更按鈕狀態(tài)
let isEnabled = textFiled.rx.text.orEmpty
.map { text in
return text.count >= 6
}
isEnabled.bind(to: button.rx.isEnabled)
.disposed(by: disposeBag)
UIScrollView
UIScrollView的用法同樣也可以訂閱我們想要的內(nèi)容,比如監(jiān)聽contentOffset變化,平時(shí)我們可能要設(shè)置delegate,然后在遵循方法,修改等等,使用rx就是一步到位,比如我們常見的向下滾動,導(dǎo)航欄透明,一行代碼就可以搞定;
func setupScrollerView() {
scrollView.rx.contentOffset
.subscribe { [weak self]content in
self?.titleView.alpha = (100-content.y)/(100)
}
.disposed(by: disposeBag)
}
手勢
手勢用起來同樣也很簡單,直接rx.event就可以
func setupGestureRecognizer() {
let tap = UITapGestureRecognizer()
self.label.addGestureRecognizer(tap)
self.label.isUserInteractionEnabled = true
tap.rx.event.subscribe { tap in
print(tap.view!)
}
.disposed(by: disposeBag)
}
通知
func setupNotification() {
NotificationCenter.default.rx.notification(UIResponder.keyboardWillShowNotification)
.subscribe { noti in
print(noti)
}
.disposed(by: disposeBag)
}
網(wǎng)絡(luò)請求
網(wǎng)絡(luò)請求步驟其實(shí)沒有比之前簡化多少,只是它幫我們做了處理,成功失敗都有區(qū)分開,無需再判斷是否有error,只關(guān)心業(yè)務(wù)實(shí)現(xiàn)就可以
func setupNetwork() {
let url = URL(string: "https://www.baidu.com")
// 正常的網(wǎng)絡(luò)請求步驟
// URLSession.shared.dataTask(with: url!) { data, response, error in
// print(String.init(data: data!, encoding: .utf8)!)
// }.resume()
URLSession.shared.rx.response(request: URLRequest(url: url!))
.subscribe(onNext: { response, data in
print(response)
}, onError: { error in
print(error)
})
.disposed(by: disposeBag)
}
定時(shí)器
這個定時(shí)器就比較有點(diǎn)不同了,實(shí)際上是個可觀察序列,給這個序列添加subscribe訂閱回調(diào),一秒回調(diào)一次
func setupTimer() {
timer = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
timer.subscribe { num in
print(num)
}
.disposed(by: disposeBag)
}
有個小細(xì)節(jié)需要注意一下,DisposeBag翻譯過來就是垃圾袋的意思,回收rx開辟的內(nèi)存的地方,如果使用局部變量DisposeBag(),容易出錯,可能函數(shù)出棧就被釋放掉了,導(dǎo)致rx真正要釋放時(shí),沒有DisposeBag可以用;建議一個類對象里面共用一個disposeBag全局變量,當(dāng)前對象被銷毀,它也跟著被釋放,
let disposeBag = DisposeBag()
// DisposeBag() 容易出問題
URLSession.shared.rx.response(request: URLRequest(url: url!))
.subscribe { response, data in
print(response)
}
.disposed(by: DisposeBag())
3、總結(jié)
像RxSwift這種函數(shù)響應(yīng)式框架其實(shí)在OC、Swift中都很常見,常見的比如Masonry,這種代碼的書寫可讀性、清晰度、可維護(hù)性都很高,當(dāng)然OC中的RAC跟RxSwift是有異曲同工之妙的,可以理解為RxSwift就是Swift版的RAC;