美文网首页RxSwift源码解析
DelegateProxy 上篇 delegate 如何转为 O

DelegateProxy 上篇 delegate 如何转为 O

作者: 狼性刀锋 | 来源:发表于2018-11-10 18:16 被阅读44次

    delegate 如何转为 Observable

    先从 UIScrollView 的扩展开始

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

    如上所见分为两种方式将delegate事件 转为 Observable ,

    1. 对DelegateProxy 已有的 Observable 进行二次封装。
    2. 通过methodInvoked 方法 , 获得 Observable

    先看看第一种怎么实现,我们一层层的看

    open class RxScrollViewDelegateProxy
       : DelegateProxy<UIScrollView, UIScrollViewDelegate>
       , DelegateProxyType 
       , UIScrollViewDelegate {
       
       
           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
       }
       
       
           public func scrollViewDidScroll(_ scrollView: UIScrollView) {
           // 代理scrollViewDidScroll 事件,并且发送消息
           if let subject = _contentOffsetBehaviorSubject {
               subject.on(.next(scrollView.contentOffset))
           }
           if let subject = _contentOffsetPublishSubject {
               subject.on(.next(()))
           }
           self._forwardToDelegate?.scrollViewDidScroll?(scrollView)
       }
       
       deinit {
       // 在deinit 时候,发出completed 事件
           if let subject = _contentOffsetBehaviorSubject {
               subject.on(.completed)
           }
    
           if let subject = _contentOffsetPublishSubject {
               subject.on(.completed)
           }
       }
       
       
       }
    
    
    

    这个原理比较简单,重点看看第二种, 先看看methodInvoked 原型

    open func methodInvoked(_ selector: Selector) -> Observable<[Any]>
    
    
    public var willBeginDecelerating: ControlEvent<Void> {
            
    let source = delegate.methodInvoked(#selector(UIScrollViewDelegate.scrollViewWillBeginDecelerating(_:))) //  Observable<[Any]>
               .map { _ in } // Observable<Void>
               return ControlEvent(events: source)
           }
           
    }
    
    

    暂时先不纠结methodInvoked 具体实现, 先看看delegate 是如何运作的?

    
    @protocol Delegate {
    
    @optional
    
    ... 可选方法
    methd_one
    
    }
    
    a.delegate = oneDelegate
    
    

    这里如果知道oneDelegate 如果没有实现 声明 methd_one 的话, 是不会进行消息转发的。 可是Rx并没有依赖这种机制, 那么Rx是怎么做到的, 答案就在于利用runtime 进行消息转发。 以下是个简单的demo

    #import "ViewController.h"
    #import <objc/runtime.h>
    
    
    @interface CustomUIScrollViewDelegate: NSObject<UIScrollViewDelegate>
        
    @end
    
    @implementation CustomUIScrollViewDelegate
        
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
          //  NSLog(@"%@", scrollView);
        NSLog(@"*****");
    }
        
    @end
    
    @interface ViewController ()<UIScrollViewDelegate> {
        CustomUIScrollViewDelegate *_delegate;
    }
    @property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
        
    @end
    
    @implementation ViewController
        
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        //  UITableView
         _delegate = [[CustomUIScrollViewDelegate alloc]init];
        self.scrollView.delegate = self;
        
    }
        
        
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
        
        
    - (BOOL)respondsToSelector:(SEL)aSelector {
            
        if( aSelector == @selector(scrollViewDidScroll:) && [_delegate respondsToSelector:aSelector])  {
            
                return YES;
            }
            
            return NO;
    }
        
        
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        // [anInvocation invoke];
        NSLog(@"forwardInvocation");
        [anInvocation invokeWithTarget:_delegate];
    }
        
        
    @end
     
    

    简单的说通过respondsToSelector 确定是否能够响应该method, 然后通过消息转发机制转发消息。 这里面有个关键就是如何确认哪些Selector 是能响应的 哪些是不能。

    阅读一下 _RXDelegateProxy 源码 (_RXDelegateProxy是所有Proxy基类)

    //
    //  _RXDelegateProxy.m
    //  RxCocoa
    //
    //  Created by Krunoslav Zaher on 7/4/15.
    //  Copyright © 2015 Krunoslav Zaher. All rights reserved.
    //
    
    #import "include/_RXDelegateProxy.h"
    #import "include/_RX.h"
    #import "include/_RXObjCRuntime.h"
    
    @interface _RXDelegateProxy () {
       id __weak __forwardToDelegate;
    }
    
    @property (nonatomic, strong) id strongForwardDelegate;
    
    @end
    
    static NSMutableDictionary *voidSelectorsPerClass = nil;
    
    @implementation _RXDelegateProxy
    
    // 递归收集协议里,返回值为void 方法 , 返回 NSSet<SEL>
    +(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;
    }
    
    // 递归收集类和父类所支持协议中所有的 返回值为void 的方法
    // voidSelectorsPerClass: NSDictionary<Class, NSSet<SEL>>
    +(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;
       }
    }
    
    //  _forwardToDelegate property
    -(id)_forwardToDelegate {
       return __forwardToDelegate;
    }
    
    -(void)_setForwardToDelegate:(id __nullable)forwardToDelegate retainDelegate:(BOOL)retainDelegate {
       __forwardToDelegate = forwardToDelegate;
       if (retainDelegate) {
           self.strongForwardDelegate = forwardToDelegate;
       }
       else {
           self.strongForwardDelegate = nil;
       }
    }
    
    
    // 是否已经定义了该方法
    -(BOOL)hasWiredImplementationForSelector:(SEL)selector {
       return [super respondsToSelector:selector];
    }
    
    // 查找该selector 是否被包含在voidSelectorsPerClass 内
    -(BOOL)voidDelegateMethodsContain:(SEL)selector {
       @synchronized(_RXDelegateProxy.class) {
           NSSet *voidSelectors = voidSelectorsPerClass[CLASS_VALUE(self.class)];
           NSAssert(voidSelectors != nil, @"Set of allowed methods not initialized");
           return [voidSelectors containsObject:SEL_VALUE(selector)];
       }
    }
    
    // 消息转发函数
    -(void)forwardInvocation:(NSInvocation *)anInvocation {
       BOOL isVoid = RX_is_method_signature_void(anInvocation.methodSignature);
       NSArray *arguments = nil;
       // 如果函数返回类型,为空 _sentMessage
       if (isVoid) {
           arguments = RX_extract_arguments(anInvocation);
           
           [self _sentMessage:anInvocation.selector withArguments:arguments];
       }
       
       // 如果 _forwardToDelegate 不为空,且响应该方法,那么转发给_forwardToDelegate
       if (self._forwardToDelegate && [self._forwardToDelegate respondsToSelector:anInvocation.selector]) {
           [anInvocation invokeWithTarget:self._forwardToDelegate];
       }
    
     // 如果函数返回类型,为空 _methodInvoked
       if (isVoid) {
           [self _methodInvoked:anInvocation.selector withArguments:arguments];
       }
    }
    
    // abstract method
    -(void)_sentMessage:(SEL)selector withArguments:(NSArray *)arguments {
    
    }
    
    // abstract method
    -(void)_methodInvoked:(SEL)selector withArguments:(NSArray *)arguments {
    
    }
    
    -(void)dealloc {
    }
    
    @end
    
    
    

    _RXDelegateProxy 主要做了一下几件事:

    1. 收集协议里所有返回值为voidSEL
    2. 提供 _forwardToDelegate 用于直接支持代理
    3. 在合适的时候进行消息转发

    好了再来分析一下DelegateProxy, 先来个前菜:DelegateProxyType

    
    public protocol DelegateProxyType: class {
    // 拥有两个范型, 一个是代理人: Delegate,一个是委托人: ParentObject
       associatedtype ParentObject: AnyObject
       associatedtype Delegate
       
       /// It is require that enumerate call `register` of the extended DelegateProxy subclasses here.
       // 注册已知的方法,具体作用后面再分析
       static func registerKnownImplementations()
    
       /// Unique identifier for delegate
       // Class 唯一标识符 , 重点要关注下这个标识符怎么产生,是用来干嘛的
       static var identifier: UnsafeRawPointer { get }
    
    
       // 设置 currentDelegate property
    
    
       static func currentDelegate(for object: ParentObject) -> Delegate?
    
    
       static func setCurrentDelegate(_ delegate: Delegate?, to object: ParentObject)
    
       // 设置 forwardToDelegate property
       func setForwardToDelegate(_ forwardToDelegate: Delegate?, retainDelegate: Bool)
    }
    
    
    
    

    看一下官方的注释

    
    
    
         +-------------------------------------------+
         |                                           |                           
         | 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)    |                           
         |                                           |
         +-------------------------------------------+                           
    
    
    
    

    使用 proxy 替代Delegate, proxy 会提供Observable 以供用户订阅, 同时proxy 提供消息转发功能, 用户可以设置 setForwardToDelegate ,兼容原来的Delegate模式

    MessageDispatcher

      fileprivate 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]>) -> () {
               return self.dispatcher.on
           }
    
           var hasObservers: Bool {
               return self.dispatcher.hasObservers
           }
    
           func asObservable() -> Observable<[Any]> {
               return self.result
           }
       }
    
    
    

    MessageDispatcher 的功能就在于, 收到相关delegate 相关消息转发的时候, 将这个消息转化为Observable.onNext事件 ,以供用户订阅。
    该Observable 是一个共享操作符,(避免do 事件被重复执行),在主线程订阅。
    至于do 事件 所做的 checkSelectorIsObservable 和 reset 是干什么待会在研究。

    终于轮到 DelegateProxy 出场了, 先看看它有什么属性

    
      open class DelegateProxy<P: AnyObject, D>: _RXDelegateProxy {
           public typealias ParentObject = P
           public typealias Delegate = D
    
           private var _sentMessageForSelector = [Selector: MessageDispatcher]()
           private var _methodInvokedForSelector = [Selector: MessageDispatcher]()
    
           /// Parent object associated with delegate proxy.
           private weak private(set) var _parentObject: ParentObject?
    
           fileprivate let _currentDelegateFor: (ParentObject) -> AnyObject?
           fileprivate let _setCurrentDelegateTo: (AnyObject?, ParentObject) -> ()
    
           /// Initializes new instance.
           ///
           /// - parameter parentObject: Optional parent object that owns `DelegateProxy` as associated object.
           public init<Proxy: DelegateProxyType>(parentObject: ParentObject, delegateProxy: Proxy.Type)
               where Proxy: DelegateProxy<ParentObject, Delegate>, Proxy.ParentObject == ParentObject, Proxy.Delegate == Delegate {
               self._parentObject = parentObject
               self._currentDelegateFor = delegateProxy._currentDelegate
               self._setCurrentDelegateTo = delegateProxy._setCurrentDelegate
    
               MainScheduler.ensureExecutingOnScheduler()
               #if TRACE_RESOURCES
                   _ = Resources.incrementTotal()
               #endif
               super.init()
           }
    }
    
    
    

    两个Dictionary<Selector, MessageDispatcher>, 一个对委托人的弱引用,一个currentDelegate 属性。 并不复杂。继续看看它的方法。

    
    // 这一段利用了懒加载的思想,只在需要的时候创建MessageDispatcher, 避免容器的资源浪费
      open func sentMessage(_ selector: Selector) -> Observable<[Any]> {
               MainScheduler.ensureExecutingOnScheduler()
    
               let subject = _sentMessageForSelector[selector]
    
               if let subject = subject {
                   return subject.asObservable()
               }
               else {
                   let subject = MessageDispatcher(selector: selector, delegateProxy: self)
                   _sentMessageForSelector[selector] = subject
                   return subject.asObservable()
               }
           }
    
    
    open func methodInvoked(_ selector: Selector) -> Observable<[Any]> {
               MainScheduler.ensureExecutingOnScheduler()
    
               let subject = _methodInvokedForSelector[selector]
    
               if let subject = subject {
                   return subject.asObservable()
               }
               else {
                   let subject = MessageDispatcher(selector: selector, delegateProxy: self)
                   _methodInvokedForSelector[selector] = subject
                   return subject.asObservable()
               }
           }
    
            // 收到消息发送 on 事件
           open override func _sentMessage(_ selector: Selector, withArguments arguments: [Any]) {
               _sentMessageForSelector[selector]?.on(.next(arguments))
           }
    
           // 收到消息发送 on 事件
           open override func _methodInvoked(_ selector: Selector, withArguments arguments: [Any]) {
               _methodInvokedForSelector[selector]?.on(.next(arguments))
           }
    

    这一段是收到消息转发的处理, 收到消息转发后由相应的MessageDispatcher 发出onNext事件。

    
            // 检测是否支持该方法代理
           private func hasObservers(selector: Selector) -> Bool {
               return (_sentMessageForSelector[selector]?.hasObservers ?? false)
                   || (_methodInvokedForSelector[selector]?.hasObservers ?? false)
           }
    
           // runtime 核心函数
           override open func responds(to aSelector: Selector!) -> Bool {
               return super.responds(to: aSelector)  // 父类是否响应该方法
                   || (self._forwardToDelegate?.responds(to: aSelector) ?? false) //  _forwardToDelegate 是否响应该方法
                   || (self.voidDelegateMethodsContain(aSelector) && self.hasObservers(selector: aSelector)) // 判断自己是否支持该方法
           }
    
    
    
    

    消息转发策略

    1. 父类响应该方法
    2. _forwardToDelegate 响应该方法
    3. 该方法包含在 voidDelegateMethodList 列表类, 且相应的MessageDispather 拥有订阅者

    其中第三条策略最为复杂, 因为前两天的返回值是确定的一旦代码编译完结果就确定了,至于第三条有点懵。 试想一下如果 MessageDispather 前一刻拥有Observers,后一刻没有, 那么是不是 前一刻的结果为true,后一刻的结果为false。于是写了个简单Demo验证一下: 传送门

    
        open func forwardToDelegate() -> Delegate? {
               return castOptionalOrFatalError(self._forwardToDelegate)
           }
    
           /// Sets reference of normal delegate that receives all forwarded messages
           /// through `self`.
           ///
           /// - parameter forwardToDelegate: Reference of delegate that receives all messages through `self`.
           /// - parameter retainDelegate: Should `self` retain `forwardToDelegate`.
           open func setForwardToDelegate(_ delegate: Delegate?, retainDelegate: Bool) {
               #if DEBUG // 4.0 all configurations
                   MainScheduler.ensureExecutingOnScheduler()
               #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) {
                   checkSelectorIsObservable(selector)
               }
    
               self.reset()
           }
    
    
    
    

    设置forwardToDelegate 属性, 这里同样有一个问题,在 不同时间段设置forwardToDelegate 属性, 最终可能 allUsedSelectors 的结果不一样。 这个同样需要验证一下。

    
            fileprivate func checkSelectorIsObservable(_ selector: Selector) {
               MainScheduler.ensureExecutingOnScheduler()
    
               if hasWiredImplementation(for: selector) {
                   print("⚠️ Delegate proxy is already implementing `\(selector)`, a more performant way of registering might exist.")
                   return
               }
    
               if voidDelegateMethodsContain(selector) {
                   return
               }
    
               // In case `_forwardToDelegate` is `nil`, it is assumed the check is being done prematurely.
               if !(self._forwardToDelegate?.responds(to: selector) ?? true) {
                   print("⚠️ Using delegate proxy dynamic interception method but the target delegate object doesn't respond to the requested selector. " +
                       "In case pure Swift delegate proxy is being used please use manual observing method by using`PublishSubject`s. " +
                       " (selector: `\(selector)`, forwardToDelegate: `\(_forwardToDelegate ?? self)`)")
               }
           }
           
           
           
    
    
    

    checkSelectorIsObservable 分为三个分支:

    1. 父类已经定义了该方法, 搜索了所有的 hasWiredImplementationForSelector方法,发现没有被重载,函数实现
    -(BOOL)hasWiredImplementationForSelector:(SEL)selector {
       return [super respondsToSelector:selector];
    }
    
    

    那么就会给出警告, 指出该方法已经在父类实现, 可能存在更高效实现方法

    1. 该SEL 返回值为void,合法直接返回
    2. 该SEL 返回值不为空 ,且在 _forwardToDelegate没有定义,这个时候会给出警告, 但是什么触发这个case 还需要研究一下。
      触发该case 传送门: 传送门
    
    // 更新delegate
            fileprivate func reset() {
               guard let parentObject = self._parentObject else { return }
    
               let maybeCurrentDelegate = _currentDelegateFor(parentObject)
    
               if maybeCurrentDelegate === self {
                   // 清空当前delegate
                   _setCurrentDelegateTo(nil, parentObject)
                 // 重新设置当前delegate
                   _setCurrentDelegateTo(castOrFatalError(self), parentObject)
               }
           }
    
    
    
    

    一下情况会触发reset 方法

    • setForwardToDelegate
    • MessageDispatcher Subscribed
    • MessageDispatcher Dispose

    相关文章

      网友评论

        本文标题:DelegateProxy 上篇 delegate 如何转为 O

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