美文网首页
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