小松的技术博客

六和敬

若今生迷局深陷,射影含沙。便许你来世袖手天下,一幕繁华。 你可愿转身落座,掌间朱砂,共我温酒煮茶。

SwiftBond源码解析(一)

众所周知,MVVM是近几年很火的一种设计模式,在前端界有Angular、Vue、Avalon等众多框架,借助这些框架,把jser从DOM操作的水深火热中解放了出来,极大的提高了前端的开发效率。而我们来看看iOS,MVVM大多时候都只是用来拆解ViewController的一种手段而已,谈不上什么高大上。但如何让它高大上起来呢?我觉得是“绑定”:实现model和view的绑定,让开发者在操作数据的时候,界面自动更新,用户对界面的操作自动映射到数据上,即去render化。因此我们需要一个框架帮我们实现“绑定“的功能。因而SwiftBond出现在了我的眼球。

所谓最好的文档就是源码了,了解它能做什么时更知晓其怎么做的。

举几个栗子

textField.bnd_text.observe { text in
    // do something you like
    print(text)
}

这个例子会监听textField的值并打印出来

textField.bnd_text.bindTo(label.bnd_text)

这个例子会自动把textField的值输出到label

combineLatest(emailField.bnd_text,passField.bnd_text)
.map { email, pass in
    return email.length > 0 && pass.length > 0
}
.bindTo(button.bnd_enabled)

这个栗子会根据emailFieldpassField的输入判断button是否应该enabled

这几个栗子还是足够能让开发者心动的吧。那我们就去看看它是如何实现的吧。

SwiftBond的上层抽象

所谓的绑定,其实也就是观察者模式的实现了,view观察到数据变了,就更新自己。ViewModel观察到view变了,就更新自己。所以SwiftBond整体上也是一个观察-订阅模型

由上图可知,SwiftBond可分为两部分,一部分是核心抽象实现,另一部分是针对iOS和OSX的具体扩展。

首先让我们聚焦在SwiftBond的抽象部分:

  • 事件产生:EventProducerType,其具体实现是EventProducer以及其子类Observable

    public protocol EventProducerType {
        associatedtype EventType
        // size
        var replayLength: Int { get }
        // 注册一个事件订阅者,和大多数框架实现一样,都是事件产出者订阅事件消费者,与日常感受相反,这样做的好处是有利于链式调用以及框架的设计
        func observe(observer: EventType -> Void) -> DisposableType
    }
    
  • 事件订阅:DisposableType以及其各个子类

    public protocol DisposableType {
        // 取消或者完成订阅关系
        func dispose()
        // 订阅关系是否还存在
        var isDisposed: Bool { get }
    }
    
  • 事件绑定:BindableType,其实质是一个事件订阅者的生成Factory,而事件订阅者就是Element -> Void(因为事件订阅重要只有一个消费事件过程,借助swift的特性,我们就没必要为事件订阅者专门建一个类,我们用这样的函数声明就可以搞定)

    public protocol BindableType {
        associatedtype Element
        // 这里比较疑惑的可能是为何要传入DisposableType,这里注释已经说明白了是为了订阅关系取消时做相关deinit的工作,后面我们可以看到其具体作用
        func sink(disconnectDisposable: DisposableType?) -> (Element -> Void)
    }
    

EventProducer

我们首先聚焦事件的产生,我们需要关注三件事情:

  • EventProducer初始化时会做些什么
  • EventProducer订阅时会做些什么
  • EventProducer派发事件时又会做些什么

EventProducer的声明如下:

public class EventProducer<Event>: EventProducerType

它是一个泛型类,并且实现了EventProducerType协议

EventProducer初始化

它有两个init方法,我们先看第一个:

public typealias Sink = Event -> Void
public init(replayLength: Int = 0, lifecycle: EventProducerLifecycle = .Managed, @noescape producer: Sink -> DisposableType?) {
    self.lifecycle = lifecycle

    let tmpSelfReference = Reference(weak: self)

    if replayLength > 0 {
      replayBuffer = Buffer(size: replayLength)
    }
    // 可以传入另一个productor,然后自己作为事件订阅者。
    let disposable = producer { event in
      tmpSelfReference.object?.next(event)
    }

    if let disposable = disposable {
      deinitDisposable += disposable
    }

    selfReference = tmpSelfReference
}

上面传参有EventProducerLifecycle,我们看看它是什么:

public enum EventProducerLifecycle {
case Normal // 正常RAC行为,有强引用时不被释放 case Managed // 框架管理,只要存在事件订阅者,就不释放 }

这里涉及了iOS的RAC、弱引用、强引用等知识。SwiftBond用了一个Reference类实现上面的.Managed行为:

public final class Reference<T: AnyObject> {
  public weak var object: T?
  private var strongReference: T?

  public init(_ object: T) {
    self.object = object
    self.strongReference = object
  }

  public init(weak object: T) {
    self.object = object
  }

  public func release() {
    strongReference = nil
  }

  public func retain() {
    strongReference = object
  }
}

这里其实就是构建一个新的类,需要retain的时候就强引用EventProductor,需要release时就释放这个强引用。只要很好的理解swift中强引用、弱引用、无主引用,上面的实现应该能够理解。

init的时候会实例化一个Buffer,这个类其实就是实现了事件的存储,产生的事件总是先缓存在这里,然后再派发给订阅者。

然后我们就需要理解deinitDisposable

public let deinitDisposable = CompositeDisposable()

CompositeDisposable的实现如下

public final class CompositeDisposable: DisposableType {

  public private(set) var isDisposed: Bool = false
  private var disposables: [DisposableType] = []
  //递归锁
  private let lock = NSRecursiveLock(name: "com.swift-bond.Bond.CompositeDisposable")

  public convenience init() {
    self.init([])
  }

  public init(_ disposables: [DisposableType]) {
    self.disposables = disposables
  }

  public func addDisposable(disposable: DisposableType) {
    lock.lock()
    if isDisposed {
      disposable.dispose()
    } else {
      disposables.append(disposable)
      self.disposables = disposables.filter { $0.isDisposed == false }
    }
    lock.unlock()
  }

  public func dispose() {
    lock.lock()
    isDisposed = true
    for disposable in disposables {
      disposable.dispose()
    }
    disposables = []
    lock.unlock()
  }
}

它的作用就是合成多次事件订阅为一次,在dispose的时候遍历所有管理下的Disposable并调用dispose。 也就是deinitDisposable适用于管理当前EventProductor的所有订阅关系。

public func += (left: CompositeDisposable, right: DisposableType) {
  left.addDisposable(right)
}

CompositeDisposable实现了+=操作符,因而可以如下使用:

deinitDisposable += disposable

而另一个init过程则是非常简单明了:

public init(replayLength: Int = 0, lifecycle: EventProducerLifecycle = .Normal) {
    self.lifecycle = lifecycle

    if replayLength > 0 {
      replayBuffer = Buffer(size: replayLength)
    }
}

EventProducer订阅

我们只需关注observe方法

public func observe(observer: Event -> Void) -> DisposableType {

    if lifecycle == .Managed {
      selfReference?.retain()
    }
    // 添加添加订阅者
    let eventProducerBaseDisposable = addObserver(observer)
    // 将Buffer中缓存的事件派发出去
    replayBuffer?.replayTo(observer)
    // 构建一个BlockDisposable,并交由deinitDisposable管理
    let observerDisposable = BlockDisposable { [weak self] in
      eventProducerBaseDisposable.dispose()

      if let unwrappedSelf = self {
        if unwrappedSelf.observers.count == 0 {
          unwrappedSelf.selfReference?.release()
        }
      }
    }

    deinitDisposable += observerDisposable
    return observerDisposable
}

具体的添加订阅者的逻辑由addObserver完成:

private func addObserver(observer: Event -> Void) -> DisposableType {
    lock.lock()
    let token = nextToken
    nextToken = nextToken + 1
    lock.unlock()

    observers[token] = observer
    return EventProducerDisposable(eventProducer: self, token: token)
}

这里会把订阅者Event -> Void保存到字典中,然后返回的是EventProducerDisposable,我们看看它的逻辑:

public final class EventProducerDisposable<EventType>: DisposableType {

  private weak var eventProducer: EventProducer<EventType>!
  private var token: Int64

  public var isDisposed: Bool {
    return eventProducer == nil
  }
  //初始化时会记录事件订阅者所属的EventProducer,并记录其在EventProducer的订阅者字典的位置
  private init(eventProducer: EventProducer<EventType>, token: Int64) {
    self.eventProducer = eventProducer
    self.token = token
  }

  public func dispose() {
    // 当dispose时会告诉EventProducer根据token移除相应的订阅者,具体可看EventProducer的removeObserver方法
    if let eventProducer = eventProducer {
      eventProducer.removeObserver(self)
      self.eventProducer = nil
    }
  }
}

根据上述的注释,我们可以知道EventProducerDisposable就是EventProducer和事件订阅者的连接者,我们可以继续追踪observe方法,看其是如何联系在一起的:

let observerDisposable = BlockDisposable { [weak self] in
      eventProducerBaseDisposable.dispose()

      if let unwrappedSelf = self {
        if unwrappedSelf.observers.count == 0 {
          unwrappedSelf.selfReference?.release()
        }
      }
}

看来我们得先知道BlockDisposable的实现:

public final class BlockDisposable: DisposableType {

  public var isDisposed: Bool {
    return handler == nil
  }

  private var handler: (() -> Void)?
  private let lock = NSRecursiveLock(name: "com.swift-bond.Bond.BlockDisposable")

  public init(_ handler: () -> Void) {
    self.handler = handler
  }

  public func dispose() {
    lock.lock()
    handler?()
    handler = nil
    lock.unlock()
  }
}

其逻辑很简单,就是开发者可以指定其在dispose时执行一个Block。而根据BlockDisposable传入的闭包,我们可以知道它会调用EventProducerDisposable的dispose方法以及做一些引用管理的工作,而这个BlockDisposable又在deinitDisposable的管理下,所以借助这些Disposable,我们在注册事件订阅者时就将其纳入EventProducer的生命周期管理下。当然observe方法会返回我们构造的BlockDisposable,所以我们可以在需要的时候调用dispose方法取消这次订阅,这时事件订阅者就会自动从EventProducer的订阅者字典中去除。

EventProducer事件派发

当我们需要把新的事件派发给事件订阅者时,我们只需要调用EventProducernext方法,其实现为:

public func next(event: Event) {
    replayBuffer?.push(event)
    dispatchNext(event)
}

具体逻辑在私有的dispatchNext中:

private func dispatchNext(event: Event) {
    guard !isDispatchInProgress else { return }

    lock.lock()
    isDispatchInProgress = true
    for (_, send) in observers {
      send(event)
    }
    isDispatchInProgress = false
    lock.unlock()
}

其逻辑很简单,遍历事件订阅者字典,然后发送事件。

到此,整个事件订阅发布流程就很清晰了。我们就能很清晰的知道调用observenext方法后会发生什么了。使用起来也就更安心了。

那我们常常使用的Observable又是什么呢?

public final class Observable<Wrapped>: EventProducer<Wrapped> {

  public var value: Wrapped {
    get {
      return replayBuffer!.last!
    }
    set {
      next(newValue)
    }
  }

  public init(_ value: Wrapped) {
    super.init(replayLength: 1)
    next(value)
  }
}

原来其只是Buffer容量为1的EventProducer。

BindableType

我们之前有说过,BindableType可以认为是事件订阅者的生成Factory。那我们其在源码中的已有实现:

extension EventProducer: BindableType {
  public func sink(disconnectDisposable: DisposableType?) -> Event -> Void {

    if let disconnectDisposable = disconnectDisposable {
      deinitDisposable += disconnectDisposable
    }

    return { [weak self] value in
      self?.next(value)
    }
  }
}

源码中EventProducer实现了BindableType,从其返回的闭包来看,它调用了自己next方法将事件传递了下去,这样可以的好处是可以实现事件的链式传递。其它的实现我们这里暂且不提。其次我们要关注的是传递进来的DisposableType,它被BindableTypedeinitDisposable管理.要想知道其的作用以及其使用,我们需要去看看“绑定”的实现。

绑定等功能的实现使用了EventProducerType的协议扩展实现的,这是swift带给我们的一个非常有用的功能,它使得swift面向协议编程成为可能。

这个协议扩展实现了一些我们常用的功能如bindTo、map、filter、deleverOn、throttle、skip等功能,我们这里只关注bindTo的实现:

public extension EventProducerType {
    public func bindTo<B: BindableType where B.Element == EventType>(bindable: B) -> DisposableType {
        let disposable = SerialDisposable(otherDisposable: nil)
        let sink = bindable.sink(disposable)
        disposable.otherDisposable = observe { value in
          sink(value)
        }
        return disposable
    }
}

这里又出现了一个SerialDisposable,我们来看看吧:

public final class SerialDisposable: DisposableType {

  public private(set) var isDisposed: Bool = false
  private let lock = NSRecursiveLock(name: "com.swift-bond.Bond.SerialDisposable")
  public var otherDisposable: DisposableType? {
    didSet {
      lock.lock()
      if isDisposed {
        otherDisposable?.dispose()
      }
      lock.unlock()
    }
  }

  public init(otherDisposable: DisposableType?) {
   self.otherDisposable = otherDisposable
  }

  public func dispose() {
    lock.lock()
    if !isDisposed {
      isDisposed = true
      otherDisposable?.dispose()
    }
    lock.unlock()
  }
}

其init时传入了另外一个DisposableType,在dispose时也dispose传入的DisposableType

知道了功能我们就可以去了解bindTo做了些什么了。

// 初始化一个SerialDisposable
let disposable = SerialDisposable(otherDisposable: nil)
//调用bindale的sink方法,返回的是一个事件订阅者
let sink = bindable.sink(disposable)
// 这里调用observe方法注册了事件订阅者
// 我们知道observe方法返回的是BlockDisposable,其中联系着EventProducer和事件订阅者
// 将BlockDisposable交由disposable管理
// 而上文在BindableType初始化时会把 disposable交由BindableType的deinitDisposable管理
//综上,BlockDisposable的既在EventProducer的deinitDisposable,又在BindableType的deinitDisposable的管理下,只要一方释放,这个绑定就不会存在了。可见框架逻辑设计的严密性
disposable.otherDisposable = observe { value in
    sink(value)
}

通过上面的分析对bindTo的分析,我们基本上可以知道EventProducerBindableType是如何相互作用的了。这样我们就对SwiftBond的抽象层有了清晰的认识了,那么它会如何在UIKit中发挥作用呢?且听下回分解。

←支付宝← →微信 →
comments powered by Disqus