UITextField是常用的控件。RxSwift对UITextField的事件.valueChanged, .editingDidBegin, .editingChanged, .editingDidEnd, .editingDidEndOnExit进行封装。
使用方法如下:
textFiled.rx.text
.subscribe(onNext: { (text) in
print("打印: \(text)") // block_1
})
运行代码:会默认执行一次block_1闭包。
如果textFiled.text = "Jensen"代码,并不会执行block_1闭包。它是怎么实现的呢?
带着疑问,我们进入源码。
textFiled.rx.text做了什么?
public var text: ControlProperty<String?> {
return value
}
返回的是一个ControlProperty对象,下图是它的继承关系:

通过她的继承关系,我们知道ControlProperty是个可观察序列,也可以作为观察者。
代码中返回了value:
public var value: ControlProperty<String?> {
return base.rx.controlPropertyWithDefaultEvents(
getter: { textField in
textField.text
},
setter: { textField, value in
// This check is important because setting text value always clears control state
// including marked text selection which is imporant for proper input
// when IME input method is used.
if textField.text != value {
textField.text = value
}
}
)
}
调用base.rx.controlPropertyWithDefaultEvents方法,参数是UITextField.text的getter、setter方法
internal func controlPropertyWithDefaultEvents<T>(
editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> Void
) -> ControlProperty<T> {
return controlProperty(
editingEvents: editingEvents,
getter: getter,
setter: setter
)
}
调用controlProperty方法初始化:
public func controlProperty<T>(
editingEvents: UIControl.Event,
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> Void
) -> ControlProperty<T> {
let source: Observable<T> = Observable.create { [weak weakControl = base] observer in
guard let control = weakControl else {
observer.on(.completed)
return Disposables.create()
}
observer.on(.next(getter(control)))
let controlTarget = ControlTarget(control: control, controlEvents: editingEvents) { _ in
if let control = weakControl {
observer.on(.next(getter(control)))
}
}
return Disposables.create(with: controlTarget.dispose)
}
.takeUntil(deallocated)
let bindingObserver = Binder(base, binding: setter)
return ControlProperty<T>(values: source, valueSink: bindingObserver)
}
controlProperty首先创建一个可观察序列source(本文将其命名为source_1,本文中再次出现source_1指的就是这个地方创建的这个可观察序列)。创建序列的逻辑实现可查看RxSwift核心逻辑分析,本文不在赘述。
let bindingObserver = Binder(base, binding: setter)创建一个Binder观察者.
public init<Target: AnyObject>(_ target: Target, scheduler: ImmediateSchedulerType = MainScheduler(), binding: @escaping (Target, Value) -> Void) {
weak var weakTarget = target
self._binding = { event in
switch event {
case .next(let element):
_ = scheduler.schedule(element) { element in
if let target = weakTarget {
binding(target, element)
}
return Disposables.create()
}
case .error(let error):
bindingError(error)
case .completed:
break
}
}
}
Binder观察者中保存了target和_binding闭包。
·ControlProperty初始化方法保存了_values和_valueSink
public init<Values: ObservableType, Sink: ObserverType>(values: Values, valueSink: Sink) where Element == Values.Element, Element == Sink.Element {
self._values = values.subscribeOn(ConcurrentMainScheduler.instance)
self._valueSink = valueSink.asObserver()
}
_valueSink就是上述创建的观察者let bindingObserver = Binder(base, binding: setter)
_values保存的是subscribeOn对象,
public func subscribeOn(_ scheduler: ImmediateSchedulerType)
-> Observable<Element> {
return SubscribeOn(source: self, scheduler: scheduler)
}
final private class SubscribeOn<Ob: ObservableType>: Producer<Ob.Element> {
let source: Ob
let scheduler: ImmediateSchedulerType
init(source: Ob, scheduler: ImmediateSchedulerType) {
self.source = source
self.scheduler = scheduler
}
}
SubscribeOn保存了values,即是上述创建的source_1
上面就是textFiled.rx.text做的事情,就是创建了一个中间层ControlProperty,保存了一个可观察序列source_1,和它的观察者对象_valueSink

订阅方法subscribe
结合RxSwift核心逻辑分析,ControlProperty重写了subscribe(observer)方法,序列的订阅会调用到ControlProperty的subscribe(observer)
public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
return self._values.subscribe(observer)
}
self._values是SubscribeOn对象,那么self._values.subscribe等价于SubscribeOn.subscribe
根据RxSwift核心逻辑分析,会调用到SubscribeOn.run方法,然后调用sink.run()
func run() -> Disposable {
let disposeEverything = SerialDisposable()
let cancelSchedule = SingleAssignmentDisposable()
disposeEverything.disposable = cancelSchedule
let disposeSchedule = self.parent.scheduler.schedule(()) { _ -> Disposable in
let subscription = self.parent.source.subscribe(self)
disposeEverything.disposable = ScheduledDisposable(scheduler: self.parent.scheduler, disposable: subscription)
return Disposables.create()
}
cancelSchedule.setDisposable(disposeSchedule)
return disposeEverything
}
self.parent.source.subscribe(self),self.parent是SubscribeOn,SubscribeOn.source正是上面创建的source_1, 根据RxSwift核心逻辑分析,调用可观察序列的subscribe,会执行可观察序列创建时传入的逃逸闭包,
let source: Observable<T> = Observable.create { [weak weakControl = base] observer in
guard let control = weakControl else {
observer.on(.completed)
return Disposables.create()
}
observer.on(.next(getter(control)))
let controlTarget = ControlTarget(control: control, controlEvents: editingEvents) { _ in
if let control = weakControl {
observer.on(.next(getter(control)))
}
}
return Disposables.create(with: controlTarget.dispose)
}
.takeUntil(deallocated)
闭包中,首先默认执行observer.on(.next(getter(control))),这也就是为什么第一次订阅会默认调用一次block_1.
然后是ControlTarget的创建
init(control: Control, controlEvents: UIControl.Event, callback: @escaping Callback) {
MainScheduler.ensureRunningOnMainThread()
self.control = control
self.controlEvents = controlEvents
self.callback = callback
super.init()
control.addTarget(self, action: selector, for: controlEvents)
let method = self.method(for: selector)
if method == nil {
rxFatalError("Can't find method")
}
}
ControlTarget中UITextField添加事件,当有时间触发时,就会调用callback,执行外界的block_1。这也就是为什么上述直接对控件赋值,无法执行block_1闭包的原因了,因为直接对控件赋值不属于事件。
总结:
上述是UITextField事件封装及调用的全过程。
简要的说,UITextField事件的封装其实是创建了中间层ControlProperty,ControlProperty保存一个内部可观察序列source_1,及其它的观察者。当调用ControlProperty.subscribe进行订阅时,内部将会转为对内部序列source_1的订阅,对source_1的订阅会执行source_1创建时的尾随闭包,闭包中首先调用一次observer.on,并添加UITextField的事件监听。
