美文网首页
RxSwift文档补充二(Delegate)

RxSwift文档补充二(Delegate)

作者: 酒茶白开水 | 来源:发表于2020-09-17 11:36 被阅读0次

    DelegateProxyType

    View只能注册一个delegate/datasource,而DelegateProxyType协议允许使用正常的delegates和Rx观察序列。

    Proxies为特定的视图存储有关observers、subscriptions和delegates的信息。

    DelegateProxyType的实现不能直接初始化,应该使用获取实现DelegateProxyTypeproxy初始化实例的方法。

    这或多或少就是DelegateProxyType的工作原理:

          +-------------------------------------------+
          |                                           |                           
          | UIView subclass (UIScrollView)            |                           
          |                                           |
          +-----------+-------------------------------+                           
                      |                                                           
                      | Delegate                                                  
                      |                                                           
                      |                                                           
          +-----------v-------------------------------+                           
          |                                           |                           
          | Delegate proxy : DelegateProxyType        +-----+---->  Observable<T1>
          |                , UIScrollViewDelegate     |     |
          +-----------+-------------------------------+     +---->  Observable<T2>
                      |                                     |                     
                      |                                     +---->  Observable<T3>
                      |                                     |                     
                      | forwards events                     |
                      | to custom delegate                  |
                      |                                     v                     
          +-----------v-------------------------------+                           
          |                                           |                           
          | Custom delegate (UIScrollViewDelegate)    |                           
          |                                           |
          +-------------------------------------------+                           
    

    因为RxCocoa需要自动创建那些代理,并且拥有delegates的View可以是继承的UITableView: UIScrollView: UIView

    相应的代理也是继承的UITableViewDelegate: UIScrollViewDelegate: NSObject

    这个机制可以通过在使用rx.*之前(例如appDidFinishLaunching),在registerKnownImplementations或程序的其他一些地方使用执行下面的代码片段来扩展。

        RxScrollViewDelegateProxy.register { RxTableViewDelegateProxy(parentObject: $0) }
    

    协议分析

    public protocol DelegateProxyType: class {
        /// 关联类型,父对象->持有代理对象的类
        associatedtype ParentObject: AnyObject
        /// 关联类型,代理->上面ParentObject的代理类
        associatedtype Delegate
        
        /// 这里需要枚举调用扩展的DelegateProxy子类的`register`
        static func registerKnownImplementations()
    
        /// 代理的唯一id
        static var identifier: UnsafeRawPointer { get }
    
        /// 返回对象特定的代理属性
        ///
        /// 对象可以有多个代理属性
        ///
        /// 每个代理属性需要在自己的类中实现`DelegateProxyType`
        ///
        /// 这是抽象方法
        ///
        /// - parameter object: 拥有代理属性的对象
        /// - returns: 代理属性的值
        static func currentDelegate(for object: ParentObject) -> Delegate?
    
        /// 为对象设置特定的代理属性
        ///
        /// 对象可以有多个代理属性
        ///
        /// 每个代理属性需要在自己的类中实现`DelegateProxyType`
        ///
        /// 这是抽象方法
        ///
        /// - parameter toObject: 拥有代理属性的对象
        /// - parameter delegate: 代理属性的值
        static func setCurrentDelegate(_ delegate: Delegate?, to object: ParentObject)
    
        /// 返回接收所有通过`self`转发的消息的正常代理的引用
        ///
        /// - returns: 引用的值或者为空
        func forwardToDelegate() -> Delegate?
    
        /// 设置接收所有通过`self`转发的消息的正常代理的引用
        ///
        /// - parameter forwardToDelegate: 接收所有通过`self`转发的消息的代理的引用
        /// - parameter retainDelegate: `self`是否强引用`forwardToDelegate`
        func setForwardToDelegate(_ forwardToDelegate: Delegate?, retainDelegate: Bool)
    }
    

    DelegateProxy

    DelegateProxy作为实现DelegateProxyType协议的基类,它的实现不是线程安全的,只能在主线程中使用。

    _RXDelegateProxy

    _RXDelegateProxyDelegateProxy的父类,由Objective-C实现,继承自NSObjective,.h文件如下:

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface _RXDelegateProxy : NSObject
    
    @property (nonatomic, weak, readonly) id _forwardToDelegate;
    
    -(void)_setForwardToDelegate:(id __nullable)forwardToDelegate retainDelegate:(BOOL)retainDelegate NS_SWIFT_NAME(_setForwardToDelegate(_:retainDelegate:)) ;
    
    -(BOOL)hasWiredImplementationForSelector:(SEL)selector;
    -(BOOL)voidDelegateMethodsContain:(SEL)selector;
    
    -(void)_sentMessage:(SEL)selector withArguments:(NSArray*)arguments;
    -(void)_methodInvoked:(SEL)selector withArguments:(NSArray*)arguments;
    
    @end
    

    首先分析几个相关的方法函数

    RX_is_method_with_description_void函数:

    BOOL RX_is_method_with_description_void(struct objc_method_description method) {
        return strncmp(method.types, @encode(void), 1) == 0;
    }
    

    代码分析:

    • 这个函数的作用是通过一个方法描述结构体objc_method_description判断此方法是否有返回值
    • 使用strncmp函数比较方法参数编码字符串和void的类型编码的第一个字符是否相等

    collectVoidSelectorsForProtocol:方法:

    +(NSSet*)collectVoidSelectorsForProtocol:(Protocol *)protocol {
        NSMutableSet *selectors = [NSMutableSet set];
    
        unsigned int protocolMethodCount = 0;
        struct objc_method_description *pMethods = protocol_copyMethodDescriptionList(protocol, NO, YES, &protocolMethodCount);
    
        for (unsigned int i = 0; i < protocolMethodCount; ++i) {
            struct objc_method_description method = pMethods[i];
            if (RX_is_method_with_description_void(method)) {
                [selectors addObject:SEL_VALUE(method.name)];
            }
        }
                
        free(pMethods);
    
        unsigned int numberOfBaseProtocols = 0;
        Protocol * __unsafe_unretained * pSubprotocols = protocol_copyProtocolList(protocol, &numberOfBaseProtocols);
    
        for (unsigned int i = 0; i < numberOfBaseProtocols; ++i) {
            [selectors unionSet:[self collectVoidSelectorsForProtocol:pSubprotocols[i]]];
        }
        
        free(pSubprotocols);
    
        return selectors;
    }
    

    代码分析:

    • 此方法的作用是返回一个协议及其继承的协议中定义的所有没有返回值的方法的集合
    • 获取该协议上定义的所有方法,将没有返回值的方法的selector转换为一个NSValue值加入到集合中
    • 获取该协议继承的所有协议,合并通过递归的方式获取协议上定义的所有没有返回值的方法的集合,然后返回

    主要方法分析

    initialize方法是在这个类接收第一条消息之前调用:

    +(void)initialize {
        @synchronized (_RXDelegateProxy.class) {
            if (voidSelectorsPerClass == nil) {
                voidSelectorsPerClass = [[NSMutableDictionary alloc] init];
            }
    
            NSMutableSet *voidSelectors = [NSMutableSet set];
    
    #define CLASS_HIERARCHY_MAX_DEPTH 100
    
            NSInteger  classHierarchyDepth = 0;
            Class      targetClass         = NULL;
    
            for (classHierarchyDepth = 0, targetClass = self;
                 classHierarchyDepth < CLASS_HIERARCHY_MAX_DEPTH && targetClass != nil;
                 ++classHierarchyDepth, targetClass = class_getSuperclass(targetClass)
            ) {
                unsigned int count;
                Protocol *__unsafe_unretained *pProtocols = class_copyProtocolList(targetClass, &count);
                
                for (unsigned int i = 0; i < count; i++) {
                    NSSet *selectorsForProtocol = [self collectVoidSelectorsForProtocol:pProtocols[i]];
                    [voidSelectors unionSet:selectorsForProtocol];
                }
                
                free(pProtocols);
            }
    
            if (classHierarchyDepth == CLASS_HIERARCHY_MAX_DEPTH) {
                NSLog(@"Detected weird class hierarchy with depth over %d. Starting with this class -> %@", CLASS_HIERARCHY_MAX_DEPTH, self);
    #if DEBUG
                abort();
    #endif
            }
            
            voidSelectorsPerClass[CLASS_VALUE(self)] = voidSelectors;
        }
    }
    

    代码分析:

    • 可变字典类型的静态变量voidSelectorsPerClass在没有值时初始化
    • 遍历该类的继承系统,然后遍历每个类遵守的协议,使用上面分析的collectVoidSelectorsForProtocol:方法拿到协议定义的没有返回值的方法集合然后合并到一起
    • 最后将该类转化为NSValue值做为key,将上面得到的集合作为值存储到voidSelectorsPerClass字典中

    _forwardToDelegate取值方法:

    -(id)_forwardToDelegate {
        return __forwardToDelegate;
    }
    

    代码分析:

    • 只读属性_forwardToDelegate的getter方法,直接返回实例变量__forwardToDelegate的值

    _setForwardToDelegate:retainDelegate:方法:

    -(void)_setForwardToDelegate:(id __nullable)forwardToDelegate retainDelegate:(BOOL)retainDelegate {
        __forwardToDelegate = forwardToDelegate;
        if (retainDelegate) {
            self.strongForwardDelegate = forwardToDelegate;
        }
        else {
            self.strongForwardDelegate = nil;
        }
    }
    

    代码分析:

    • forwardToDelegate赋值给实例变量__forwardToDelegate
    • 根据retainDelegate决定是否把forwardToDelegate赋值给strongForwardDelegate强引用属性

    非常重要的一个方法forwardInvocation:

    -(void)forwardInvocation:(NSInvocation *)anInvocation {
        BOOL isVoid = RX_is_method_signature_void(anInvocation.methodSignature);
        NSArray *arguments = nil;
        if (isVoid) {
            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) {
            [self _methodInvoked:anInvocation.selector withArguments:arguments];
        }
    }
    

    代码分析:

    • 该方法是在接受到一个未知消息进行消息转发时调用的,可以移步我以前的一篇博客了解消息转发
    • 首先判断未知消息是否有返回值
    • 如果该未知消息没有返回值就获取消息的参数列表并执行_sentMessage:withArguments:方法
    • 如果_forwardToDelegate属性能够响应该消息,将该未知消息转发给_forwardToDelegate属性对象
    • 最后如果该未知消息没有返回值就执行_methodInvoked:withArguments:方法

    DelegateProxyFactory

    遵守DelegateProxyType协议的代理对象的工厂类,主要作用是存储生成遵守DelegateProxyType协议的代理对象的闭包。

    初始化:

            private var _factories: [ObjectIdentifier: ((AnyObject) -> AnyObject)]
            private var _delegateProxyType: Any.Type
            private var _identifier: UnsafeRawPointer
    
            private init<DelegateProxy: DelegateProxyType>(for proxyType: DelegateProxy.Type) {
                self._factories = [:]
                self._delegateProxyType = proxyType
                self._identifier = proxyType.identifier
            }
    

    代码分析:

    • _factories属性使用空字典初始化
    • _delegateProxyType属性使用遵守DelegateProxyType协议的代理类初始化
    • _identifier属性使用遵守DelegateProxyType协议的代理类的id初始化

    extend函数:

            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.")
                    }
                    self._factories[ObjectIdentifier(ParentObject.self)] = { make(castOrFatalError($0)) }
            }
    

    代码分析:

    • 首先保证在主线程
    • 保证_identifier属性的值与泛型DelegateProxyidentifier类属性相等
    • 保证_factories属性字典中没有存储以泛型ParentObject相应的ObjectIdentifier作为key的值
    • 以泛型ParentObject相应的ObjectIdentifier作为key,将生成Rx代理对象的闭包存在_factories属性中

    createProxy函数:

    fileprivate func createProxy(for object: AnyObject) -> AnyObject {
                MainScheduler.ensureRunningOnMainThread()
                var maybeMirror: Mirror? = Mirror(reflecting: object)
                while let mirror = maybeMirror {
                    if let factory = self._factories[ObjectIdentifier(mirror.subjectType)] {
                        return factory(object)
                    }
                    maybeMirror = mirror.superclassMirror
                }
                rxFatalError("DelegateProxy has no factory of \(object). Implement DelegateProxy subclass for \(object) first.")
            }
    

    代码分析:

    • 首先保证在主线程
    • 遍历参数对象的继承系统,用类相应的ObjectIdentifier作为key_factories属性中获取生成Rx代理对象的闭包,取到闭包就返回执行闭包的结果
    • 最终取不到闭包就终止

    类属性_sharedFactories是以代理的id作为key、工厂对象作为值的字典,用于缓存各遵守DelegateProxyType协议的代理类的工厂对象:

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

    sharedFactory函数根据遵守DelegateProxyType协议的代理类的id获取对应的工厂对象,代码如下:

            fileprivate static func sharedFactory<DelegateProxy: DelegateProxyType>(for proxyType: DelegateProxy.Type) -> DelegateProxyFactory {
                MainScheduler.ensureRunningOnMainThread()
                let identifier = DelegateProxy.identifier
                if let factory = _sharedFactories[identifier] {
                    return factory
                }
                let factory = DelegateProxyFactory(for: proxyType)
                _sharedFactories[identifier] = factory
                DelegateProxy.registerKnownImplementations()
                return factory
            }
    

    代码分析:

    • 保证在主线程
    • 根据遵守DelegateProxyType协议的代理类id从_sharedFactories字典中获取工厂对象,取到就返回
    • _sharedFactories字典中取不到工厂对象,就创建一个并存到字典中
    • 执行遵守DelegateProxyType协议的代理类的registerKnownImplementations函数并返回工厂对象

    MessageDispatcher

    MessageDispatcher的本质是一个PublishSubject,把协议中的每个函数对应一个MessageDispatcher,进而将函数的调用转化为Observable序列,其实现如下:

        private final class MessageDispatcher {
            private let dispatcher: PublishSubject<[Any]>
            private let result: Observable<[Any]>
    
            fileprivate let selector: Selector
    
            init<P, D>(selector: Selector, delegateProxy _delegateProxy: DelegateProxy<P, D>) {
                weak var weakDelegateProxy = _delegateProxy
    
                let dispatcher = PublishSubject<[Any]>()
                self.dispatcher = dispatcher
                self.selector = selector
    
                self.result = dispatcher
                    .do(onSubscribed: { weakDelegateProxy?.checkSelectorIsObservable(selector); weakDelegateProxy?.reset() }, onDispose: { weakDelegateProxy?.reset() })
                    .share()
                    .subscribeOn(mainScheduler)
            }
    
            var on: (Event<[Any]>) -> Void {
                return self.dispatcher.on
            }
    
            var hasObservers: Bool {
                return self.dispatcher.hasObservers
            }
    
            func asObservable() -> Observable<[Any]> {
                return self.result
            }
        }
    

    代码分析:

    • 初始化时创建一个PublishSubject存储在dispatcher属性中
    • 初始化时将dispatcher属性中存储的PublishSubject执行do操作符,并在PublishSubject被订阅后执行代理对象的checkSelectorIsObservable函数检查是否能将selector转化为Observable序列,然后执行代理对象的reset函数重新设置代理。在PublishSubject销毁时执行代理对象的reset函数重新设置代理。然后执行share操作共享元素,接着执行subscribeOn(mainScheduler)操作保证序列在主线程中执行各种操作,最后将最终得到的Observable序列存储到result属性中
    • on函数直接调用dispatcher属性中存储的PublishSubjecton操作
    • asObservable函数直接返回初始化时构造好的result属性

    DelegateProxy实现

    首先分析一下DelegateProxy的属性:

    • _sentMessageForSelector属性是一个以SelectorkeyMessageDispatcher为值的字典
    • _methodInvokedForSelector属性也是一个以SelectorkeyMessageDispatcher为值的字典,与_sentMessageForSelector相比主要是他们存储的MessageDispatcher使用的时机不同(后面再讲)
    • _parentObject属性存储持有代理对象的对象
    • _currentDelegateFor属性是一个闭包,用来获取_parentObject属性的代理对象
    • _setCurrentDelegateTo属性也是一个闭包,用来设置_parentObject属性的代理对象

    sentMessage函数分析:

            open func sentMessage(_ selector: Selector) -> Observable<[Any]> {
                MainScheduler.ensureRunningOnMainThread()
    
                let subject = self._sentMessageForSelector[selector]
    
                if let subject = subject {
                    return subject.asObservable()
                }
                else {
                    let subject = MessageDispatcher(selector: selector, delegateProxy: self)
                    self._sentMessageForSelector[selector] = subject
                    return subject.asObservable()
                }
            }
    

    代码分析:

    • 使用selector参数从_sentMessageForSelector属性中取MessageDispatcher对象,
    • 取到值就转化为Observable序列返回
    • 没有取到值就创建一个MessageDispatcher对象,存储到_sentMessageForSelector属性中,然后转化为Observable序列返回

    methodInvoked函数的实现与上面分析的函数相同。

    checkSelectorIsObservable函数分析:

    • 该函数的作用是检查selector参数对应的函数是否能够转化为Observable序列
    • 首先检查自己没有实现selector参数对应的函数
    • 接着检查自己遵守的协议定义的没有返回值的函数集合包含有selector参数对应的函数
    • 最后检查_forwardToDelegate属性不能响应selector参数对应的函数

    _sentMessage_methodInvoked函数分析:

            open override func _sentMessage(_ selector: Selector, withArguments arguments: [Any]) {
                self._sentMessageForSelector[selector]?.on(.next(arguments))
            }
    
            open override func _methodInvoked(_ selector: Selector, withArguments arguments: [Any]) {
                self._methodInvokedForSelector[selector]?.on(.next(arguments))
            }
    

    代码分析:

    • _sentMessage_methodInvoked函数都只是取出对应的MessageDispatcher对象,然后执行on操作来发射元素
    • 此时应该联系DelegateProxy的父类_RXDelegateProxyforwardInvocation:方法来分析
    • 在收到没有返回值的未知消息时,会先后执行这两个方法(注意它们的执行顺序)

    DelegateProxyType扩展重要函数实现

    register函数就是把生成对象闭包存储到DelegateProxyFactory中:

        private static var factory: DelegateProxyFactory {
            return DelegateProxyFactory.sharedFactory(for: self)
        }
        public static func register<Parent>(make: @escaping (Parent) -> Self) {
            self.factory.extend(make: make)
        }
    

    代码分析:

    • DelegateProxyFactory.sharedFactory首次调用时内部会调用registerKnownImplementations函数
    • 前面说过需要在实现registerKnownImplementations函数时调用实现的代理类的register函数注册一个代理对象生成的闭包
    • DelegateProxyFactoryextend函数就是用来存储代理对象生成闭包的

    proxy函数:

        public static func createProxy(for object: AnyObject) -> Self {
            return castOrFatalError(factory.createProxy(for: object))
        }
        public static func proxy(for object: ParentObject) -> Self {
            MainScheduler.ensureRunningOnMainThread()
    
            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 {
                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
        }
    

    代码分析:

    • 首先使用runtime技术中的assignedProxy函数获取关联属性,其实就是缓存的代理对象
    • 如果没有值就执行createProxy函数,其实就是从DelegateProxyFactory中取出注册的生成Rx代理对象的闭包执行,进而生成Rx代理对象
    • 获取参数ParentObject的代理对象
    • 如果代理对象和Rx代理对象不是同一个对象,那么将代理对象赋值给Rx代理对象的forwardToDelegate属性,将Rx代理对象作为参数ParentObject真正的代理对象
    • 返回Rx代理对象

    总结

    罗里吧嗦的分析这么久的代码,感觉调理不是很清楚,最后总结下,Rx中代理的实现过程,就以UIScrollViewDelegate协议的Rx实现为例。

    首先构建类RxScrollViewDelegateProxy继承DelegateProxy基类,同时遵守DelegateProxyTypeUIScrollViewDelegate协议协议。在RxScrollViewDelegateProxy中实现registerKnownImplementations函数,为遵守UIScrollViewDelegate协议的对象注册一个Rx代理对象生成的闭包:

    open class RxScrollViewDelegateProxy
        : DelegateProxy<UIScrollView, UIScrollViewDelegate>
        , DelegateProxyType 
        , UIScrollViewDelegate {
        public init(scrollView: ParentObject) {
            self.scrollView = scrollView
            super.init(parentObject: scrollView, delegateProxy: RxScrollViewDelegateProxy.self)
        }
        public static func registerKnownImplementations() {
            self.register { RxScrollViewDelegateProxy(scrollView: $0) }
            self.register { RxTableViewDelegateProxy(tableView: $0) }
            self.register { RxCollectionViewDelegateProxy(collectionView: $0) }
            self.register { RxTextViewDelegateProxy(textView: $0) }
        }
    }
    

    说明:此处的registerKnownImplementations函数把UIScrollViewDelegate协议的子协议的Rx代理对象的生成闭包一并注册了。

    DelegateProxyType协议定义的下面只读属性在DelegateProxyType扩展中已经实现,所以不需要不实现:

    extension DelegateProxyType { UnsafeRawPointer {
            let delegateIdentifier = ObjectIdentifier(Delegate.self)
            let integerIdentifier = Int(bitPattern: delegateIdentifier)
            return UnsafeRawPointer(bitPattern: integerIdentifier)!
        }
    }
    

    DelegateProxyType协议定义的下面两个函数在DelegateProxyType扩展中已经实现:

    extension DelegateProxyType where ParentObject: HasDelegate, Self.Delegate == ParentObject.Delegate {
        public static func currentDelegate(for object: ParentObject) -> Delegate? {
            return object.delegate
        }
    
        public static func setCurrentDelegate(_ delegate: Delegate?, to object: ParentObject) {
            object.delegate = delegate
        }
    }
    

    上面DelegateProxyType协议定义的两个函数虽然在DelegateProxyType扩展中已经实现但是需要满足两个条件:

    • 持有Rx代理对象的类必须遵守HasDelegate协议
    • Self.Delegate的类型和持有Rx代理对象的类的Delegate类型必须相同

    所以扩展UIScrollView类,让其准守HasDelegate协议并且让Delegate类型和Rx代理对象的类的Delegate类型必须相同:

    extension UIScrollView: HasDelegate {
        public typealias Delegate = UIScrollViewDelegate
    }
    

    DelegateProxyType协议定义的下面两个函数在Rx代理基类DelegateProxy中已经实现,也不需要再实现了:

            open func forwardToDelegate() -> Delegate? {
                return castOptionalOrFatalError(self._forwardToDelegate)
            }
            open func setForwardToDelegate(_ delegate: Delegate?, retainDelegate: Bool) {
                #if DEBUG // 4.0 all configurations
                    MainScheduler.ensureRunningOnMainThread()
                #endif
                self._setForwardToDelegate(delegate, retainDelegate: retainDelegate)
    
                let sentSelectors: [Selector] = self._sentMessageForSelector.values.filter { $0.hasObservers }.map { $0.selector }
                let invokedSelectors: [Selector] = self._methodInvokedForSelector.values.filter { $0.hasObservers }.map { $0.selector }
                let allUsedSelectors = sentSelectors + invokedSelectors
    
                for selector in Set(allUsedSelectors) {
                    self.checkSelectorIsObservable(selector)
                }
    
                self.reset()
            }
    

    协议函数的Observeble序列实现

    有两种方法可以将协议中的函数实现为Observeble序列

    Subject方式

    这种方式需要在RxScrollViewDelegateProxy类中,定义对应的UIScrollViewDelegate协议中函数对应的Subject,并且实现UIScrollViewDelegate协议的函数,在协议的函数中调用Subjecton操作来发射元素:

        private var _contentOffsetBehaviorSubject: BehaviorSubject<CGPoint>?
        private var _contentOffsetPublishSubject: PublishSubject<()>?
        
        internal var contentOffsetBehaviorSubject: BehaviorSubject<CGPoint> {
            if let subject = _contentOffsetBehaviorSubject {
                return subject
            }
    
            let subject = BehaviorSubject<CGPoint>(value: self.scrollView?.contentOffset ?? CGPoint.zero)
            _contentOffsetBehaviorSubject = subject
    
            return subject
        }
        internal var contentOffsetPublishSubject: PublishSubject<()> {
            if let subject = _contentOffsetPublishSubject {
                return subject
            }
    
            let subject = PublishSubject<()>()
            _contentOffsetPublishSubject = subject
    
            return subject
        }
        
        public func scrollViewDidScroll(_ scrollView: UIScrollView) {
            if let subject = _contentOffsetBehaviorSubject {
                subject.on(.next(scrollView.contentOffset))
            }
            if let subject = _contentOffsetPublishSubject {
                subject.on(.next(()))
            }
            self._forwardToDelegate?.scrollViewDidScroll?(scrollView)
        }
        
        deinit {
            if let subject = _contentOffsetBehaviorSubject {
                subject.on(.completed)
            }
    
            if let subject = _contentOffsetPublishSubject {
                subject.on(.completed)
            }
        }
    

    说明:开头就说了DelegateProxyType协议允许使用正常的delegates和Rx观察序列,因为RxScrollViewDelegateProxy.proxy(for: base)中的proxy操作会将正常的代理对象存储到Rx代理对象的forwardToDelegate属性中,所以在协议函数的实现中调一下forwardToDelegate对象的协议函数,达到对正常代理对象的支持(可以参看上面相应的代码分析)。

    使用RxScrollViewDelegateProxy.proxy(for: base)提供一个Rx代理对象,为了方便一般都是封装到一个BaseUIScrollView类的Reactive扩展中,最后拿到相应的Subject将其转化为Observeble序列即可:

    public var didScroll: ControlEvent<Void> {
                let source = RxScrollViewDelegateProxy.proxy(for: base).contentOffsetPublishSubject
                return ControlEvent(events: source)
            }
    

    消息转发方式

    消息转发方式不需要实现UIScrollViewDelegate协议中函数,因为没有实现,所以会走基类_RXDelegateProxy的消息转发方法forwardInvocation:(可参看前面相应的代码分析),主要做了如下三件事:

    • 执行_sentMessage:withArguments:方法
    • 将未知消息转发给_forwardToDelegate属性对象
    • 执行_methodInvoked:withArguments:方法

    _sentMessage:withArguments:_methodInvoked:withArguments:方法在基类DelegateProxy中都已实现(可以参看上面相应的代码分析),主要就是根据selector获取相应的MessageDispatcher(可以参看上面相应的代码分析)对象执行on操作发射元素。将未知消息转发给_forwardToDelegate属性对象是为了对正常代理对象的支持。

    基类_RXDelegateProxy暴露sentMessagemethodInvoked函数(可以参看上面相应的代码分析)根据selector构建相应的MessageDispatcher对象,并转化为Observeble序列。

    综上所述,所以直接执行Rx代理对象的sentMessagemethodInvoked函数就可以获得相应的Observeble序列:

        extension Reactive where Base: UIScrollView {
            public var delegate: DelegateProxy<UIScrollView, UIScrollViewDelegate> {
                return RxScrollViewDelegateProxy.proxy(for: base)
            }
            public var willBeginDecelerating: ControlEvent<Void> {
                let source = delegate.methodInvoked(#selector(UIScrollViewDelegate.scrollViewWillBeginDecelerating(_:))).map { _ in }
                return ControlEvent(events: source)
            }
        }
    

    相关文章

      网友评论

          本文标题:RxSwift文档补充二(Delegate)

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