RxCocoa初探
在最初接触 RxSwift 的时候我们就学到了一些很基础的用法,其中就有 UIBotton 的示例:
self.btn.rx.tap
.subscribe(onNext: { () in
print("clicked me")
}).disposed(by: disposeBag)
在 RxSwift 的万物皆序列的绝对领域中,UI事件也都被封装成了序列。这些UI响应是什么时候变成了序列了呢?
demo 中这一行代码,最先扎眼的就是.rx
了,它前面还是原来的味道,.rx 后变脸了,出来个又像手势却跟 button 玩暧昧的 tap!那就从 rx 着手调查吧!
extension ReactiveCompatible {
public static var rx: RxSwift.Reactive<Self>.Type
public var rx: RxSwift.Reactive<Self>
}
点进去原来是ReactiveCompatible
的拓展。
public struct Reactive<Base> {
public let base: Base
public init(_ base: Base) {
self.base = base
}
}
public protocol ReactiveCompatible {
associatedtype ReactiveBase
@available(*, deprecated, message: "Use `ReactiveBase` instead.")
typealias CompatibleType = ReactiveBase
static var rx: Reactive<ReactiveBase>.Type { get set }
var rx: Reactive<ReactiveBase> { get set }
}
extension ReactiveCompatible {
public var rx: Reactive<Self> {
get {
return Reactive(self)
}
set {
// this enables using Reactive to "mutate" base object
}
}
}
import class Foundation.NSObject
extension NSObject: ReactiveCompatible { }
原来是调用了一个 getter,然后用 self 作为基础对象初始化了一个 Reactive
结构体。而且NSObject
也是遵守ReactiveCompatible
协议的。也就是说所有对象都可以通过这个 getter 转成Reactive
。那么UIButton
和Reactive
是什么关系呢?我们看下RxCocoa
中UIButton
的分类:
extension Reactive where Base: UIButton {
public var tap: ControlEvent<Void> {
return controlEvent(.touchUpInside)
}
}
第一行就是对UIButton
的约束拓展。也是我们最常用的点击事件.touchUpInside
。controlEvent(.touchUpInside)
绝对不能漏掉:
extension Reactive where Base: UIControl {
public func controlEvent(_ controlEvents: UIControl.Event) -> ControlEvent<()> {
let source: Observable<Void> = Observable.create { [weak control = self.base] observer in
MainScheduler.ensureRunningOnMainThread()
guard let control = control else {
observer.on(.completed)
return Disposables.create()
}
let controlTarget = ControlTarget(control: control, controlEvents: controlEvents) { _ in
observer.on(.next(()))
}
return Disposables.create(with: controlTarget.dispose)
}
.takeUntil(deallocated)
return ControlEvent(events: source)
}
}
来到了UIControl
的拓展里了。这个实现时曾相识啊,跟RxSwift特征序列s里的封装手法一致。
这个函数返回了一个把Observable
当做源序列的ControlEvent
序列。ControlEvent
是个结构体,遵守着ControlEventType
协议,它是ObservableType
的子协议。所以这个ControlEvent
也有序列的功能。
返回创建好的ControlEvent
序列后,就是订阅了:
public struct ControlEvent<PropertyType> : ControlEventType {
let _events: Observable<PropertyType>
public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
return self._events.subscribe(observer)
}
}
ControlEvent
序列的订阅好干脆,直接让_events
(也就是它的源序列)去订阅。
从Observable
的订阅到create闭包
的回调都开通地铁直达了。再回头看create闭包
里面:
-
MainScheduler.ensureRunningOnMainThread()
:如果需要会提示不在主线程 - 如果UI控件不存在就直接发出
.completed
- 创建
ControlTarget
对象,它是RxTarget
和NSObject
的子类
final class ControlTarget: RxTarget {
typealias Callback = (Control) -> Void
let selector: Selector = #selector(ControlTarget.eventHandler(_:))
weak var control: Control?
let controlEvents: UIControl.Event
var callback: Callback?
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")
}
}
@objc func eventHandler(_ sender: Control!) {
if let callback = self.callback, let control = self.control {
callback(control)
}
}
}
在ControlTarget
的初始化中,设置好UI控件的 target,action,controlEvents。坐等系统响应,然后在eventHandler
中回调发送.next
响应订阅。
网友评论