RxSwift 下代理转可观察序列的源码解析

image.png

废话开篇:上面的流程图只是概况,对于细节部分还是有很多要注意的地方,下面就对整个代理源码进行下梳理

一、新建封装代理类

1、WSLProtocol 类

image.png

2、WSLClass 类

image.png

3、RxWSLDelegateProxy 类

image.png

4、对 WSLClass 类进行 RX 扩展

image.png

二、解析 RxWSLDelegateProxy 与 WSLClass 绑定关系

image.png

解释一下上面的流程图:

1、proxy 初始化绑定关系的开端
public static func proxy(for object: ParentObject) -> Self {

        MainScheduler.ensureRunningOnMainThread()
        //获取关联 Proxy 对象
        let maybeProxy = self.assignedProxy(for: object)
        let proxy: AnyObject

        if let existingProxy = maybeProxy {
            proxy = existingProxy
        }
        else {
            //不存在,进行创建(创建过程中进行了缓存)
            proxy = castOrFatalError(self.createProxy(for: object))
            //进行关联
            self.assignProxy(proxy, toObject: object)

            assert(self.assignedProxy(for: object) === proxy)

        }
        //获取当前代理对象
        let currentDelegate = self._currentDelegate(for: object)

        let delegateProxy: Self = castOrFatalError(proxy)

        if currentDelegate !== delegateProxy {
            //若存在真实的代理对象,就进行临时保存及设置新的代理为 Proxy 对象
            delegateProxy._setForwardToDelegate(currentDelegate, retainDelegate: false)

            assert(delegateProxy._forwardToDelegate() === currentDelegate)
            //设置新代理
            self._setCurrentDelegate(proxy, to: object)

            assert(self._currentDelegate(for: object) === proxy)

            assert(delegateProxy._forwardToDelegate() === currentDelegate)

        }

       return delegateProxy

    }
复制代码

其实逻辑到这里还是清晰的,因为就是将需要的设置代理的对象(ParentObject)的代理关系转移了一下。下面看看第一次下的 createProxy 方法做了哪些事。

2、Proxy 类 createProxy 方法的执行
public static func createProxy(for object: AnyObject) -> Self {

        return castOrFatalError(factory.createProxy(for: object))
 }
复制代码

castOrFatalError 这个方法可以先忽略,它是一段安全保护代码。

可以看到 factory.createProxy,这里的 factory 是一个类型为 DelegateProxyFactory 的静态对象。

先说过一下 DelegateProxyFactory 类,个人理解,它其实是一个具有缓存代码逻辑中已注册过的 Proxy 对象功能的类,它缓存的最终其实是一段代码,就是之前提到的 Proxy 对象下 registerKnownImplementations方法下执行 register 方法时传进来的闭包代码块,因为这个闭包代码块是一个可以返回的 Proxy 对象的,所以就相当于每次都会调用缓存下来的闭包,然后返回 Proxy 对象,再将 Proxy 对象设置为 ParentObject 对象的代理。

如图:

image.png

红圈处的尾随闭包参数其实是要缓存的目标。

那么,DelegateProxyFactory 类的缓存逻辑是什么?

image.png

DelegateProxyFactory 类做了两层的 map 查找,

(1)DelegateProxyFactory 下静态 _sharedFactories map 缓存 DelegateProxyFactory 对象
private class DelegateProxyFactory

private static var _sharedFactories: [UnsafeRawPointer: DelegateProxyFactory] = [:]

fileprivate static func sharedFactory<DelegateProxy: DelegateProxyType>(for proxyType: DelegateProxy.Type) -> DelegateProxyFactory {
            MainScheduler.ensureRunningOnMainThread()
            //获取指针
            let identifier = DelegateProxy.identifier
            //查找 factory 对象
            if let factory = _sharedFactories[identifier] {
                //这个方法会先执行一次,因为后面 registerKnownImplementations()方法会再次获取 factory 对象并进行注册扩展逻辑
                return factory

            }

            let factory = DelegateProxyFactory(for: proxyType)
            //保存
            _sharedFactories[identifier] = factory
            //因为未注册过,这里就调用外部的 registerKnownImplementations 方法进行注册
            DelegateProxy.registerKnownImplementations()

            return factory
}
复制代码

这个方法也只是返回 factory 对象,而程序需要 DelegateProxy 对象,接下来看看 factory 对象缓存 DelegateProxy 对象逻辑。

(2)DelegateProxyFactory 对象缓存 DelegateProxy 对象

由于之前 DelegateProxy.registerKnownImplementations() 方法的调用会触发 register 方法的执行

image.png

看看 register 方法实现逻辑。

public static func register<Parent>(make: @escaping (Parent) -> Self) {
        self.factory.extend(make: make)
}
复制代码

factory 对象执行了 extend 方法,此时的 factory 对象已经是全局注册过的,所以直接可用。

fileprivate func extend<DelegateProxy: DelegateProxyType, ParentObject>(make: @escaping (ParentObject) -> DelegateProxy) {

                MainScheduler.ensureRunningOnMainThread()

                precondition(self._identifier == DelegateProxy.identifier, "Delegate proxy has inconsistent identifier")

                guard self._factories[ObjectIdentifier(ParentObject.self)] == nil else {

                    rxFatalError("The factory of \(ParentObject.self) is duplicated. DelegateProxy is not allowed of duplicated base object type.")

                }
                //根据需代理对象的类型进行缓存一个闭包方法,闭包方法里执行的是 register 方法的逃逸闭包参数,这里就清楚了,在执行的时候就会获取到 DelegateProxy 对象了
                self._factories[ObjectIdentifier(ParentObject.self)] = { make(castOrFatalError($0)) }

        }
复制代码

到这里,缓存已经完毕,需要再回头看一下 DelegateProxy 下的 createProxy方法里关于 factory 执行 createProxy 方法

image.png

fileprivate func createProxy(for object: AnyObject) -> AnyObject {

            //保证在主线程
            MainScheduler.ensureRunningOnMainThread()
            //对象映射
            var maybeMirror: Mirror? = Mirror(reflecting: object)

            while let mirror = maybeMirror {
                //获取 ParentObject 类型,factory 根据 ParentObject 类型从缓存中获取闭包
                if let factory = self._factories[ObjectIdentifier(mirror.subjectType)] {
                    //执行闭包,返回闭包返回值(DelegateProxy 对象)
                    return factory(object)
                }

                maybeMirror = mirror.superclassMirror

            }
            rxFatalError("DelegateProxy has no factory of \(object). Implement DelegateProxy subclass for \(object) first.")

        }
复制代码

到这里 DelegateProxy 对象的缓存就完成了。

三、methodInvoked 方法解析

open func methodInvoked( _ selector: Selector) -> Observable<[Any]> {

            MainScheduler.ensureRunningOnMainThread()

            let subject = self._methodInvokedForSelector[selector]

            if let subject = subject {

                return subject.asObservable()

            }

            else {

                let subject = MessageDispatcher(selector: selector, delegateProxy: self)

                self._methodInvokedForSelector[selector] = subject

                return subject.asObservable()
            }
        }
复制代码

methodInvoked 通过 Selector 作为 key 从缓存中返回一个任务序列,如果没有则进行创建并缓存。

四、基于 runtime 获取对象及其父类遵循的所有代理协议及重写 respondsToSelector 方法

1、为什么要获取对象及其父类遵循的代理协议

因为,DelegateProxy 对象在做 methodInvoked 方法的时候会传进来一个 SEL 参数,那么,先获取对象及其父类遵循的所有代理协议,判断 SEL 是不是代理方法。如果是就将 DelegateProxy 对象执行 respondsToSelector 判断 SEL 是否能响应的状态返回 YES,进而出发 runtime 的消息转发逻辑。

open class DelegateProxy<P: AnyObject, D>: _RXDelegateProxy
复制代码

DelegateProxy 其实继承的是 _RXDelegateProxy 类,_RXDelegateProxy 类是 OC 的类。

//第一次收到消息时执行
+(void)initialize;
//收集所有遵循的代理方法(包括父类...)
+(NSSet*)collectVoidSelectorsForProtocol:(Protocol *)protocol;
复制代码

两个方法配合调用缓存了该对象及其父类(父类->父类...)所有的代理方法。

-(void)forwardInvocation:(NSInvocation *)anInvocation {

    BOOL isVoid = RX_is_method_signature_void(anInvocation.methodSignature);

    NSArray *arguments = nil;

    if (isVoid) {
        //执行 _sentMessageForSelector 集合下 selector 对应的任务序列
        arguments = RX_extract_arguments(anInvocation);

        [self _sentMessage:anInvocation.selector withArguments:arguments];

    }

    if (self._forwardToDelegate && [self._forwardToDelegate respondsToSelector:anInvocation.selector]) {
        //执行代理方法
        [anInvocation invokeWithTarget:self._forwardToDelegate];

    }

    if (isVoid) {
        //执行 _methodInvokedForSelector 集合下 selector 对应的任务序列
        [self _methodInvoked:anInvocation.selector withArguments:arguments];

    }

}
复制代码

进行消息转发,触发对应的任务序列执行 .on(.next()) 方法。

这里的 _sentMessage_methodInvoked 与可以理解为切面截断方法,对象存在代理的条件下, _sentMessage 是代理执行前执行,_methodInvoked 是代理执行后执行。

_methodInvoked 为例:

open override func _methodInvoked( _ selector: Selector, withArguments arguments: [Any]) {
       //根据传过来的 SEL 获取缓存在 _methodInvokedForSelector 里的任务序列进行并执行
       self._methodInvokedForSelector[selector]?.on(.next(arguments))
 }
复制代码
2、为什么要重写 respondsToSelector 方法

因为,对于系统级的 delegate 方法,如:tableView 的点击事件,本身就有安全保护措施,不重写此方法,不会进行消息转发的。

override open func responds(to aSelector: Selector!) -> Bool {

            return super.responds(to: aSelector)

                || (self._forwardToDelegate?.responds(to: aSelector) ?? false)
                //这里判断 aSelector 是不是代理方法,并且可以进行任务序列的触发
                || (self.voidDelegateMethodsContain(aSelector) && self.hasObservers(selector: aSelector))

}
复制代码

最终实现了代理转序列的逻辑

五、思考

源码内容其实很多,个人总结肯定有瑕疵,互相交流,共同进步[抱拳]

猜你喜欢

转载自juejin.im/post/7048105663901204511