美文网首页
RxCocoa初探

RxCocoa初探

作者: silasjs | 来源:发表于2019-08-05 17:26 被阅读0次

    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。那么UIButtonReactive是什么关系呢?我们看下RxCocoaUIButton的分类:

    extension Reactive where Base: UIButton {
        public var tap: ControlEvent<Void> {
            return controlEvent(.touchUpInside)
        }
    }
    

    第一行就是对UIButton的约束拓展。也是我们最常用的点击事件.touchUpInsidecontrolEvent(.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对象,它是RxTargetNSObject的子类
    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响应订阅。

    相关文章

      网友评论

          本文标题:RxCocoa初探

          本文链接:https://www.haomeiwen.com/subject/eutvdctx.html