為什么要使用 RxSwift ?
我們先看一下 RxSwift 能夠幫助我們做些什么:
Target Action
傳統(tǒng)實現(xiàn)方法:
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
func buttonTapped() {
print("button Tapped")
}
通過 Rx 來實現(xiàn):
button.rx.tap
.subscribe(onNext: {
print("button Tapped")
})
.disposed(by: disposeBag)
你不需要使用 Target Action,這樣使得代碼邏輯清晰可見。
代理
傳統(tǒng)實現(xiàn)方法:
class ViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("contentOffset: \(scrollView.contentOffset)")
}
}
通過 Rx 來實現(xiàn):
class ViewController: UIViewController {
...
override func viewDidLoad() {
super.viewDidLoad()
scrollView.rx.contentOffset
.subscribe(onNext: { contentOffset in
print("contentOffset: \(contentOffset)")
})
.disposed(by: disposeBag)
}
}
你不需要書寫代理的配置代碼,就能獲得想要的結(jié)果。
閉包回調(diào)
傳統(tǒng)實現(xiàn)方法:
URLSession.shared.dataTask(with: URLRequest(url: url)) {
(data, response, error) in
guard error == nil else {
print("Data Task Error: \(error!)")
return
}
guard let data = data else {
print("Data Task Error: unknown")
return
}
print("Data Task Success with count: \(data.count)")
}.resume()
通過 Rx 來實現(xiàn):
URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(onNext: { data in
print("Data Task Success with count: \(data.count)")
}, onError: { error in
print("Data Task Error: \(error)")
})
.disposed(by: disposeBag)
回調(diào)也變得十分簡單
通知
傳統(tǒng)實現(xiàn)方法:
var ntfObserver: NSObjectProtocol!
override func viewDidLoad() {
super.viewDidLoad()
ntfObserver = NotificationCenter.default.addObserver(
forName: .UIApplicationWillEnterForeground,
object: nil, queue: nil) { (notification) in
print("Application Will Enter Foreground")
}
}
deinit {
NotificationCenter.default.removeObserver(ntfObserver)
}
通過 Rx 來實現(xiàn):
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.rx
.notification(.UIApplicationWillEnterForeground)
.subscribe(onNext: { (notification) in
print("Application Will Enter Foreground")
})
.disposed(by: disposeBag)
}
你不需要去管理觀察者的生命周期,這樣你就有更多精力去關(guān)注業(yè)務(wù)邏輯。
KVO
傳統(tǒng)實現(xiàn)方法:
private var observerContext = 0
override func viewDidLoad() {
super.viewDidLoad()
user.addObserver(self, forKeyPath: #keyPath(User.name), options: [.new, .initial], context: &observerContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &observerContext {
let newValue = change?[.newKey] as? String
print("do something with newValue")
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
deinit {
user.removeObserver(self, forKeyPath: #keyPath(User.name))
}
通過 Rx 來實現(xiàn):
override func viewDidLoad() {
super.viewDidLoad()
user.rx.observe(String.self, #keyPath(User.name))
.subscribe(onNext: { newValue in
print("do something with newValue")
})
.disposed(by: disposeBag)
}
這樣實現(xiàn) KVO 的代碼更清晰,更簡潔并且更準確。
多個任務(wù)之間有依賴關(guān)系
例如,先通過用戶名密碼取得 Token 然后通過 Token 取得用戶信息,
傳統(tǒng)實現(xiàn)方法:
/// 用回調(diào)的方式封裝接口
enum Api {
/// 通過用戶名密碼取得一個 token
static func token(username: String, password: String,
success: (String) -> Void,
failure: (Error) -> Void) { ... }
/// 通過 token 取得用戶信息
static func userinfo(token: String,
success: (UserInfo) -> Void,
failure: (Error) -> Void) { ... }
}
/// 通過用戶名和密碼獲取用戶信息
Api.token(username: "beeth0ven", password: "987654321",
success: { token in
Api.userInfo(token: token,
success: { userInfo in
print("獲取用戶信息成功: \(userInfo)")
},
failure: { error in
print("獲取用戶信息失敗: \(error)")
})
},
failure: { error in
print("獲取用戶信息失敗: \(error)")
})
通過 Rx 來實現(xiàn):
/// 用 Rx 封裝接口
enum Api {
/// 通過用戶名密碼取得一個 token
static func token(username: String, password: String) -> Observable<String> { ... }
/// 通過 token 取得用戶信息
static func userInfo(token: String) -> Observable<UserInfo> { ... }
}
/// 通過用戶名和密碼獲取用戶信息
Api.token(username: "beeth0ven", password: "987654321")
.flatMapLatest(Api.userInfo)
.subscribe(onNext: { userInfo in
print("獲取用戶信息成功: \(userInfo)")
}, onError: { error in
print("獲取用戶信息失敗: \(error)")
})
.disposed(by: disposeBag)
這樣你無需嵌套太多層,從而使得代碼易讀,易維護。
等待多個并發(fā)任務(wù)完成后處理結(jié)果
例如,需要將兩個網(wǎng)絡(luò)請求合并成一個,
通過 Rx 來實現(xiàn):
/// 用 Rx 封裝接口
enum Api {
/// 取得老師的詳細信息
static func teacher(teacherId: Int) -> Observable<Teacher> { ... }
/// 取得老師的評論
static func teacherComments(teacherId: Int) -> Observable<[Comment]> { ... }
}
/// 同時取得老師信息和老師評論
Observable.zip(
Api.teacher(teacherId: teacherId),
Api.teacherComments(teacherId: teacherId)
).subscribe(onNext: { (teacher, comments) in
print("獲取老師信息成功: \(teacher)")
print("獲取老師評論成功: \(comments.count) 條")
}, onError: { error in
print("獲取老師信息或評論失敗: \(error)")
})
.disposed(by: disposeBag)
這樣你可用寥寥幾行代碼來完成相當復(fù)雜的異步操作。
那么為什么要使用 RxSwift ?
- 復(fù)合 - Rx 就是復(fù)合的代名詞
- 復(fù)用 - 因為它易復(fù)合
- 清晰 - 因為聲明都是不可變更的
- 易用 - 因為它抽象的了異步編程,使我們統(tǒng)一了代碼風格
- 穩(wěn)定 - 因為 Rx 是完全通過單元測試的