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 {
return value
}
返回的是一个ControlProperty
对象,下图是它的继承关系:
通过她的继承关系,我们知道ControlProperty是个可观察序列,也可以作为观察者。
代码中返回了value
:
public var value: ControlProperty {
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(
editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> Void
) -> ControlProperty {
return controlProperty(
editingEvents: editingEvents,
getter: getter,
setter: setter
)
}
调用controlProperty
方法初始化:
public func controlProperty(
editingEvents: UIControl.Event,
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> Void
) -> ControlProperty {
let source: Observable = 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(values: source, valueSink: bindingObserver)
}
controlProperty
首先创建一个可观察序列source
(本文将其命名为source_1
,本文中再次出现source_1
指的就是这个地方创建的这个可观察序列)。创建序列的逻辑实现可查看RxSwift核心逻辑分析,本文不在赘述。
let bindingObserver = Binder(base, binding: setter)
创建一个Binder观察者.
public init(_ 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: 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 {
return SubscribeOn(source: self, scheduler: scheduler)
}
final private class SubscribeOn: Producer {
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: 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 = 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
的事件监听。