swift-响应式编程

Posted by sunzhongliang on January 10, 2021

响应式编程

响应式编程(Reactive Programming),简称RP,是一种面向数据流和变化传播的编程范式,可以简化异步编程,提供更优雅的数据绑定(举个不恰当的例子,有点类似于vue或者是react当中state发生变化时可以及时的更新UI)。
swift当中比较著名成熟的框架有两个

  1. ReactiveCocoa
    官网: https://reactivecocoa.io/
    github: https://github.com/ReactiveCocoa/ReactiveCocoa/
  2. ReactiveX
    官网: http://reactivex.io/
    github: https://github.com/ReactiveX/RxSwift

RxSwift

RxSwift(reactive for swift), ReactiveX的swift版本
源码:https://github.com/ReactiveX/RxSwift
中文文档:https://beeth0ven.github.io/RxSwift-Chinese-Documentation/

RxSwift的核心角色

  • Observable 负责发送事件(Event)
  • Observer 负责订阅Observable,监听Observable发送的事件(Event)

RxSwift源码(Event.swift)关于Event描述如下

/// Represents a sequence event.
///
/// Sequence grammar: 
/// **next\* (error | completed)**
public enum Event<Element> {
    /// Next element is produced.
    case next(Element)

    /// Sequence terminated with an error.
    case error(Swift.Error)

    /// Sequence completed successfully.
    case completed
}

所以,Event有3种

  1. next: 携带具体的数据
  2. error: 携带错误信息,表明Observable终止,不会再发出事件
  3. completed: 表明Observable终止,不会再发出事件


创建Observable

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 发消息
    let observable = Observable<Int>.create { (observer) -> Disposable in
        observer.onNext(123)  // 发送了123消息
        return Disposables.create()
    }
    // 也可以采用这种方式发送订阅消息,代表只发送一个1,然后就结束
    // Observable.just(1)

    // 这种方式代表发送三次,分别是1、2、3,然后结束
    // Observable.from([1,2,3])
    
    // 订阅
    observable.subscribe { (event) in
        switch event {
        case .next(let element):
            print("element:", element)
        case .error(let error):
            print("error:", error)
        case .completed:
            print("completed")
        }
    }
    // 第二种订阅方式
    observable.subscribe { (element) in
        
    } onError: { (error) in
        
    } onCompleted: {
        
    } onDisposed: {
        
    }
}

比如我们在做控件开发的时候,需要将一个定时器的的值显示在label上面:

// 代表两秒之后,每隔一秒执行一次
let observable = Observable<Int>.timer(.seconds(2), period: .seconds(1), scheduler: MainScheduler.instance)

// 绑定到控件上面
observable.map{"text:\($0)"}.bind(to: label.rx.text)


Disposables
每当Observable被订阅的时候都会返回一个Observable的实例,调用Observabledispose就相当于取消订阅

// 代表两秒之后,每隔一秒执行一次
let observable = Observable<Int>.timer(.seconds(2), period: .seconds(1), scheduler: MainScheduler.instance)

// 绑定到控件上面
let observer = observable.map{"text:\($0)"}.bind(to: label.rx.text)
observer.dispose()

对于取消订阅,有以下几种方式

  1. 立即取消订阅
     // 订阅方法之后紧跟着dispose方法取消订阅
     observable.subscribe { (event) in
         print(event)
     }.dispose()
    
  2. 当bag(被控制器或者其他对象持有)销毁(deinit)时,会自动调用Disposables实例的dispose
     let bag = DisposeBag();
     observable.subscribe { (event) in
         print(event)
     }.disposed(by: bag)
    
  3. 代表这一个订阅会跟随控制器的生命周期
     observable.takeUntil(self.rx.deallocated).map{"\($0)"}.bind(to: label.rx.text)
    

传统状态监听方式

传统的监听方案:

  1. KVO
  2. Target-Action
  3. Notification
  4. delegate
  5. Block / Callback

传统方案通常会出现错综复杂的依赖关系,耦合性比较高,

比如我们现在需要做一个按钮的点击, 传统方案的实现方式:

button.addTarget(self, action: #selector(buttonClick(_:)), for: .touchUpInside);

新的实现方案是:

button.rx.controlEvent(.touchUpInside).subscribe(onNext: {
    print("按钮被点击了")
}).disposed(by: bag)

还有比如我们在做网络请求的时候,model有变化的时候需要刷新界面,这时候通过RxSwift状态监听实现,就非常方便了

class Dog: NSObject {
    @objc dynamic var name: String?
}

let dog = Dog()
dog.rx.observe(String.self, "name").subscribe { (name) in
    print(name)
}
dog.name = "dog"

本文首次发布于 孙忠良 Blog, 作者 [@sunzhongliang] , 转载请保留原文链接.