• 为什么要使用 RxSwift ?
    • Target Action
    • 代理
    • 闭包回调
    • 通知
    • KVO
    • 多个任务之间有依赖关系
    • 等待多个并发任务完成后处理结果
      • 那么为什么要使用 RxSwift ?

    为什么要使用 RxSwift ?

    我们先看一下 RxSwift 能够帮助我们做些什么:


    Target Action

    传统实现方法:

    1. button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    1. func buttonTapped() {
    2. print("button Tapped")
    3. }

    通过 Rx 来实现:

    1. button.rx.tap
    2. .subscribe(onNext: {
    3. print("button Tapped")
    4. })
    5. .disposed(by: disposeBag)

    你不需要使用 Target Action,这样使得代码逻辑清晰可见。


    代理

    传统实现方法:

    1. class ViewController: UIViewController {
    2. ...
    3. override func viewDidLoad() {
    4. super.viewDidLoad()
    5. scrollView.delegate = self
    6. }
    7. }
    8. extension ViewController: UIScrollViewDelegate {
    9. func scrollViewDidScroll(_ scrollView: UIScrollView) {
    10. print("contentOffset: \(scrollView.contentOffset)")
    11. }
    12. }

    通过 Rx 来实现:

    1. class ViewController: UIViewController {
    2. ...
    3. override func viewDidLoad() {
    4. super.viewDidLoad()
    5. scrollView.rx.contentOffset
    6. .subscribe(onNext: { contentOffset in
    7. print("contentOffset: \(contentOffset)")
    8. })
    9. .disposed(by: disposeBag)
    10. }
    11. }

    你不需要书写代理的配置代码,就能获得想要的结果。


    闭包回调

    传统实现方法:

    1. URLSession.shared.dataTask(with: URLRequest(url: url)) {
    2. (data, response, error) in
    3. guard error == nil else {
    4. print("Data Task Error: \(error!)")
    5. return
    6. }
    7. guard let data = data else {
    8. print("Data Task Error: unknown")
    9. return
    10. }
    11. print("Data Task Success with count: \(data.count)")
    12. }.resume()

    通过 Rx 来实现:

    1. URLSession.shared.rx.data(request: URLRequest(url: url))
    2. .subscribe(onNext: { data in
    3. print("Data Task Success with count: \(data.count)")
    4. }, onError: { error in
    5. print("Data Task Error: \(error)")
    6. })
    7. .disposed(by: disposeBag)

    回调也变得十分简单


    通知

    传统实现方法:

    1. var ntfObserver: NSObjectProtocol!
    2. override func viewDidLoad() {
    3. super.viewDidLoad()
    4. ntfObserver = NotificationCenter.default.addObserver(
    5. forName: .UIApplicationWillEnterForeground,
    6. object: nil, queue: nil) { (notification) in
    7. print("Application Will Enter Foreground")
    8. }
    9. }
    10. deinit {
    11. NotificationCenter.default.removeObserver(ntfObserver)
    12. }

    通过 Rx 来实现:

    1. override func viewDidLoad() {
    2. super.viewDidLoad()
    3. NotificationCenter.default.rx
    4. .notification(.UIApplicationWillEnterForeground)
    5. .subscribe(onNext: { (notification) in
    6. print("Application Will Enter Foreground")
    7. })
    8. .disposed(by: disposeBag)
    9. }

    你不需要去管理观察者的生命周期,这样你就有更多精力去关注业务逻辑。


    KVO

    传统实现方法:

    1. private var observerContext = 0
    2. override func viewDidLoad() {
    3. super.viewDidLoad()
    4. user.addObserver(self, forKeyPath: #keyPath(User.name), options: [.new, .initial], context: &observerContext)
    5. }
    6. override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    7. if context == &observerContext {
    8. let newValue = change?[.newKey] as? String
    9. print("do something with newValue")
    10. } else {
    11. super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    12. }
    13. }
    14. deinit {
    15. user.removeObserver(self, forKeyPath: #keyPath(User.name))
    16. }

    通过 Rx 来实现:

    1. override func viewDidLoad() {
    2. super.viewDidLoad()
    3. user.rx.observe(String.self, #keyPath(User.name))
    4. .subscribe(onNext: { newValue in
    5. print("do something with newValue")
    6. })
    7. .disposed(by: disposeBag)
    8. }

    这样实现 KVO 的代码更清晰,更简洁并且更准确。


    多个任务之间有依赖关系

    例如,先通过用户名密码取得 Token 然后通过 Token 取得用户信息,

    传统实现方法:

    1. /// 用回调的方式封装接口
    2. enum Api {
    3. /// 通过用户名密码取得一个 token
    4. static func token(username: String, password: String,
    5. success: (String) -> Void,
    6. failure: (Error) -> Void) { ... }
    7. /// 通过 token 取得用户信息
    8. static func userinfo(token: String,
    9. success: (UserInfo) -> Void,
    10. failure: (Error) -> Void) { ... }
    11. }
    1. /// 通过用户名和密码获取用户信息
    2. Api.token(username: "beeth0ven", password: "987654321",
    3. success: { token in
    4. Api.userInfo(token: token,
    5. success: { userInfo in
    6. print("获取用户信息成功: \(userInfo)")
    7. },
    8. failure: { error in
    9. print("获取用户信息失败: \(error)")
    10. })
    11. },
    12. failure: { error in
    13. print("获取用户信息失败: \(error)")
    14. })

    通过 Rx 来实现:

    1. /// 用 Rx 封装接口
    2. enum Api {
    3. /// 通过用户名密码取得一个 token
    4. static func token(username: String, password: String) -> Observable<String> { ... }
    5. /// 通过 token 取得用户信息
    6. static func userInfo(token: String) -> Observable<UserInfo> { ... }
    7. }
    1. /// 通过用户名和密码获取用户信息
    2. Api.token(username: "beeth0ven", password: "987654321")
    3. .flatMapLatest(Api.userInfo)
    4. .subscribe(onNext: { userInfo in
    5. print("获取用户信息成功: \(userInfo)")
    6. }, onError: { error in
    7. print("获取用户信息失败: \(error)")
    8. })
    9. .disposed(by: disposeBag)

    这样你无需嵌套太多层,从而使得代码易读,易维护。


    等待多个并发任务完成后处理结果

    例如,需要将两个网络请求合并成一个,

    通过 Rx 来实现:

    1. /// 用 Rx 封装接口
    2. enum Api {
    3. /// 取得老师的详细信息
    4. static func teacher(teacherId: Int) -> Observable<Teacher> { ... }
    5. /// 取得老师的评论
    6. static func teacherComments(teacherId: Int) -> Observable<[Comment]> { ... }
    7. }
    1. /// 同时取得老师信息和老师评论
    2. Observable.zip(
    3. Api.teacher(teacherId: teacherId),
    4. Api.teacherComments(teacherId: teacherId)
    5. ).subscribe(onNext: { (teacher, comments) in
    6. print("获取老师信息成功: \(teacher)")
    7. print("获取老师评论成功: \(comments.count) 条")
    8. }, onError: { error in
    9. print("获取老师信息或评论失败: \(error)")
    10. })
    11. .disposed(by: disposeBag)

    这样你可用寥寥几行代码来完成相当复杂的异步操作。


    那么为什么要使用 RxSwift ?

    • 复合 - Rx 就是复合的代名词
    • 复用 - 因为它易复合
    • 清晰 - 因为声明都是不可变更的
    • 易用 - 因为它抽象的了异步编程,使我们统一了代码风格
    • 稳定 - 因为 Rx 是完全通过单元测试的