RxSwift文档补充二(Delegate)

2020-09-17  本文已影响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;
}

代码分析:

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;
}

代码分析:

主要方法分析

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;
    }
}

代码分析:

_forwardToDelegate取值方法:

-(id)_forwardToDelegate {
    return __forwardToDelegate;
}

代码分析:

_setForwardToDelegate:retainDelegate:方法:

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

代码分析:

非常重要的一个方法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];
    }
}

代码分析:

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
        }

代码分析:

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

代码分析:

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.")
        }

代码分析:

类属性_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
        }

代码分析:

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
        }
    }

代码分析:

DelegateProxy实现

首先分析一下DelegateProxy的属性:

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()
            }
        }

代码分析:

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

checkSelectorIsObservable函数分析:

_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))
        }

代码分析:

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

代码分析:

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
    }

代码分析:

总结

罗里吧嗦的分析这么久的代码,感觉调理不是很清楚,最后总结下,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扩展中已经实现但是需要满足两个条件:

所以扩展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:_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)
        }
    }
上一篇下一篇

猜你喜欢

热点阅读