RxSwift源码解析

DelegateProxy 上篇 delegate 如何转为 O

2018-11-10  本文已影响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 方法

上一篇下一篇

猜你喜欢

热点阅读