ReactiveX(簡寫: Rx) 是一個可以幫助我們簡化異步編程的框架。
RxSwift 是 Rx 的 Swift 版本。
將KVO,異步操作 和 流 全部被統一成抽象序列
什么要使用 RxSwift ?
- 復合 - Rx 就是復合的代名詞
- 復用 - 因為它易復合
- 清晰 - 因為聲明都是不可變更的
- 易用 - 因為它抽象了異步編程,使我們統一了代碼風格
- 穩定 - 因為 Rx 是完全通過單元測試的
RxSwift 能夠幫助我們做些什么:
Target Action
傳統實現方法:
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) func buttonTapped() { print("button Tapped") }
通過 Rx 來實現:
button.rx.tap .subscribe(onNext: { print("button Tapped") }) .disposed(by: disposeBag)
不需要使用 Target Action,這樣使得代碼邏輯清晰可見。
代理
傳統實現方法:
class ViewController: UIViewController { ... override func viewDidLoad() { super.viewDidLoad() scrollView.delegate = self } } extension ViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { print("contentOffset: \(scrollView.contentOffset)") } }
通過 Rx 來實現:
class ViewController: UIViewController { ... override func viewDidLoad() { super.viewDidLoad() scrollView.rx.contentOffset .subscribe(onNext: { contentOffset in print("contentOffset: \(contentOffset)") }) .disposed(by: disposeBag) } }
不需要書寫代理的配置代碼,就能獲得想要的結果.
閉包回調
傳統實現方法:
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 來實現:
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)
回調也變得十分簡單
通知
傳統實現方法:
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 來實現:
override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.rx .notification(.UIApplicationWillEnterForeground) .subscribe(onNext: { (notification) in print("Application Will Enter Foreground") }) .disposed(by: disposeBag) }
不需要去管理觀察者的生命周期,這樣就有更多精力去關注業務邏輯。
多個任務之間有依賴關系
例如,先通過用戶名密碼取得 Token 然后通過 Token 取得用戶信息,
傳統實現方法:
/// 用回調的方式封裝接口 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 來實現:
/// 用 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)
這樣可以避免回調地獄,從而使得代碼易讀,易維護。
等待多個並發任務完成后處理結果
例如,需要將兩個網絡請求合並成一個,
通過 Rx 來實現:
/// 用 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)
這樣幾行代碼來完成相當復雜的異步操作。