DelegateProxyType
View只能注冊一個delegate/datasource觉阅,而DelegateProxyType
協(xié)議允許使用正常的delegates
和Rx觀察序列擂仍。
Proxies
為特定的視圖存儲有關observers沫换、subscriptions和delegates的信息鼎天。
DelegateProxyType
的實現(xiàn)不能直接初始化,應該使用獲取實現(xiàn)DelegateProxyType
水慨、proxy
初始化實例的方法蔚叨。
這或多或少就是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需要自動創(chuàng)建那些代理,并且擁有delegates
的View可以是繼承的UITableView: UIScrollView: UIView
相應的代理也是繼承的UITableViewDelegate: UIScrollViewDelegate: NSObject
這個機制可以通過在使用rx.*
之前(例如appDidFinishLaunching)粥诫,在registerKnownImplementations
或程序的其他一些地方使用執(zhí)行下面的代碼片段來擴展油航。
RxScrollViewDelegateProxy.register { RxTableViewDelegateProxy(parentObject: $0) }
協(xié)議分析
public protocol DelegateProxyType: class {
/// 關聯(lián)類型,父對象->持有代理對象的類
associatedtype ParentObject: AnyObject
/// 關聯(lián)類型怀浆,代理->上面ParentObject的代理類
associatedtype Delegate
/// 這里需要枚舉調(diào)用擴展的DelegateProxy子類的`register`
static func registerKnownImplementations()
/// 代理的唯一id
static var identifier: UnsafeRawPointer { get }
/// 返回對象特定的代理屬性
///
/// 對象可以有多個代理屬性
///
/// 每個代理屬性需要在自己的類中實現(xiàn)`DelegateProxyType`
///
/// 這是抽象方法
///
/// - parameter object: 擁有代理屬性的對象
/// - returns: 代理屬性的值
static func currentDelegate(for object: ParentObject) -> Delegate?
/// 為對象設置特定的代理屬性
///
/// 對象可以有多個代理屬性
///
/// 每個代理屬性需要在自己的類中實現(xiàn)`DelegateProxyType`
///
/// 這是抽象方法
///
/// - parameter toObject: 擁有代理屬性的對象
/// - parameter delegate: 代理屬性的值
static func setCurrentDelegate(_ delegate: Delegate?, to object: ParentObject)
/// 返回接收所有通過`self`轉(zhuǎn)發(fā)的消息的正常代理的引用
///
/// - returns: 引用的值或者為空
func forwardToDelegate() -> Delegate?
/// 設置接收所有通過`self`轉(zhuǎn)發(fā)的消息的正常代理的引用
///
/// - parameter forwardToDelegate: 接收所有通過`self`轉(zhuǎn)發(fā)的消息的代理的引用
/// - parameter retainDelegate: `self`是否強引用`forwardToDelegate`
func setForwardToDelegate(_ forwardToDelegate: Delegate?, retainDelegate: Bool)
}
DelegateProxy
DelegateProxy作為實現(xiàn)DelegateProxyType
協(xié)議的基類谊囚,它的實現(xiàn)不是線程安全的,只能在主線程中使用执赡。
_RXDelegateProxy
_RXDelegateProxy
是DelegateProxy
的父類镰踏,由Objective-C實現(xiàn),繼承自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
首先分析幾個相關的方法函數(shù)
RX_is_method_with_description_void
函數(shù):
BOOL RX_is_method_with_description_void(struct objc_method_description method) {
return strncmp(method.types, @encode(void), 1) == 0;
}
代碼分析:
- 這個函數(shù)的作用是通過一個方法描述結構體
objc_method_description
判斷此方法是否有返回值 - 使用
strncmp
函數(shù)比較方法參數(shù)編碼字符串和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;
}
代碼分析:
- 此方法的作用是返回一個協(xié)議及其繼承的協(xié)議中定義的所有沒有返回值的方法的集合
- 獲取該協(xié)議上定義的所有方法奠伪,將沒有返回值的方法的
selector
轉(zhuǎn)換為一個NSValue
值加入到集合中 - 獲取該協(xié)議繼承的所有協(xié)議,合并通過遞歸的方式獲取協(xié)議上定義的所有沒有返回值的方法的集合灌诅,然后返回
主要方法分析
initialize
方法是在這個類接收第一條消息之前調(diào)用:
+(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;
}
}
代碼分析:
- 可變字典類型的靜態(tài)變量
voidSelectorsPerClass
在沒有值時初始化 - 遍歷該類的繼承系統(tǒng)芳来,然后遍歷每個類遵守的協(xié)議,使用上面分析的
collectVoidSelectorsForProtocol:
方法拿到協(xié)議定義的沒有返回值的方法集合然后合并到一起 - 最后將該類轉(zhuǎn)化為
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
- 根據(jù)
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];
}
}
代碼分析:
- 該方法是在接受到一個未知消息進行消息轉(zhuǎn)發(fā)時調(diào)用的,可以移步我以前的一篇博客了解消息轉(zhuǎn)發(fā)
- 首先判斷未知消息是否有返回值
- 如果該未知消息沒有返回值就獲取消息的參數(shù)列表并執(zhí)行
_sentMessage:withArguments:
方法 - 如果
_forwardToDelegate
屬性能夠響應該消息挎袜,將該未知消息轉(zhuǎn)發(fā)給_forwardToDelegate
屬性對象 - 最后如果該未知消息沒有返回值就執(zhí)行
_methodInvoked:withArguments:
方法
DelegateProxyFactory
遵守DelegateProxyType
協(xié)議的代理對象的工廠類顽聂,主要作用是存儲生成遵守DelegateProxyType
協(xié)議的代理對象的閉包。
初始化:
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
協(xié)議的代理類初始化 -
_identifier
屬性使用遵守DelegateProxyType
協(xié)議的代理類的id初始化
extend
函數(shù):
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
屬性的值與泛型DelegateProxy
的identifier
類屬性相等 - 保證
_factories
屬性字典中沒有存儲以泛型ParentObject
相應的ObjectIdentifier
作為key
的值 - 以泛型
ParentObject
相應的ObjectIdentifier
作為key
盯仪,將生成Rx代理對象的閉包存在_factories
屬性中
createProxy
函數(shù):
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.")
}
代碼分析:
- 首先保證在主線程
- 遍歷參數(shù)對象的繼承系統(tǒng)紊搪,用類相應的
ObjectIdentifier
作為key
從_factories
屬性中獲取生成Rx代理對象的閉包,取到閉包就返回執(zhí)行閉包的結果 - 最終取不到閉包就終止
類屬性_sharedFactories
是以代理的id作為key全景、工廠對象作為值的字典耀石,用于緩存各遵守DelegateProxyType
協(xié)議的代理類的工廠對象:
private static var _sharedFactories: [UnsafeRawPointer: DelegateProxyFactory] = [:]
sharedFactory
函數(shù)根據(jù)遵守DelegateProxyType
協(xié)議的代理類的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
}
代碼分析:
- 保證在主線程
- 根據(jù)遵守
DelegateProxyType
協(xié)議的代理類id從_sharedFactories
字典中獲取工廠對象爸黄,取到就返回 -
_sharedFactories
字典中取不到工廠對象滞伟,就創(chuàng)建一個并存到字典中 - 執(zhí)行遵守
DelegateProxyType
協(xié)議的代理類的registerKnownImplementations
函數(shù)并返回工廠對象
MessageDispatcher
MessageDispatcher
的本質(zhì)是一個PublishSubject
揭鳞,把協(xié)議中的每個函數(shù)對應一個MessageDispatcher
,進而將函數(shù)的調(diào)用轉(zhuǎn)化為Observable
序列梆奈,其實現(xiàn)如下:
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
}
}
代碼分析:
- 初始化時創(chuàng)建一個
PublishSubject
存儲在dispatcher
屬性中 - 初始化時將
dispatcher
屬性中存儲的PublishSubject
執(zhí)行do
操作符野崇,并在PublishSubject
被訂閱后執(zhí)行代理對象的checkSelectorIsObservable
函數(shù)檢查是否能將selector
轉(zhuǎn)化為Observable
序列,然后執(zhí)行代理對象的reset
函數(shù)重新設置代理亩钟。在PublishSubject
銷毀時執(zhí)行代理對象的reset
函數(shù)重新設置代理乓梨。然后執(zhí)行share
操作共享元素,接著執(zhí)行subscribeOn(mainScheduler)
操作保證序列在主線程中執(zhí)行各種操作清酥,最后將最終得到的Observable
序列存儲到result
屬性中 -
on
函數(shù)直接調(diào)用dispatcher
屬性中存儲的PublishSubject
的on
操作 -
asObservable
函數(shù)直接返回初始化時構造好的result
屬性
DelegateProxy實現(xiàn)
首先分析一下DelegateProxy
的屬性:
-
_sentMessageForSelector
屬性是一個以Selector
為key
以MessageDispatcher
為值的字典 -
_methodInvokedForSelector
屬性也是一個以Selector
為key
以MessageDispatcher
為值的字典扶镀,與_sentMessageForSelector
相比主要是他們存儲的MessageDispatcher
使用的時機不同(后面再講) -
_parentObject
屬性存儲持有代理對象的對象 -
_currentDelegateFor
屬性是一個閉包,用來獲取_parentObject
屬性的代理對象 -
_setCurrentDelegateTo
屬性也是一個閉包焰轻,用來設置_parentObject
屬性的代理對象
sentMessage
函數(shù)分析:
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
參數(shù)從_sentMessageForSelector
屬性中取MessageDispatcher
對象狈惫, - 取到值就轉(zhuǎn)化為
Observable
序列返回 - 沒有取到值就創(chuàng)建一個
MessageDispatcher
對象,存儲到_sentMessageForSelector
屬性中鹦马,然后轉(zhuǎn)化為Observable
序列返回
methodInvoked
函數(shù)的實現(xiàn)與上面分析的函數(shù)相同。
checkSelectorIsObservable
函數(shù)分析:
- 該函數(shù)的作用是檢查
selector
參數(shù)對應的函數(shù)是否能夠轉(zhuǎn)化為Observable
序列 - 首先檢查自己沒有實現(xiàn)
selector
參數(shù)對應的函數(shù) - 接著檢查自己遵守的協(xié)議定義的沒有返回值的函數(shù)集合包含有
selector
參數(shù)對應的函數(shù) - 最后檢查
_forwardToDelegate
屬性不能響應selector
參數(shù)對應的函數(shù)
_sentMessage
和_methodInvoked
函數(shù)分析:
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
函數(shù)都只是取出對應的MessageDispatcher
對象忆肾,然后執(zhí)行on
操作來發(fā)射元素 - 此時應該聯(lián)系
DelegateProxy
的父類_RXDelegateProxy
的forwardInvocation:
方法來分析 - 在收到?jīng)]有返回值的未知消息時荸频,會先后執(zhí)行這兩個方法(注意它們的執(zhí)行順序)
DelegateProxyType擴展重要函數(shù)實現(xiàn)
register
函數(shù)就是把生成對象閉包存儲到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
首次調(diào)用時內(nèi)部會調(diào)用registerKnownImplementations
函數(shù) - 前面說過需要在實現(xiàn)
registerKnownImplementations
函數(shù)時調(diào)用實現(xiàn)的代理類的register
函數(shù)注冊一個代理對象生成的閉包 -
DelegateProxyFactory
的extend
函數(shù)就是用來存儲代理對象生成閉包的
proxy
函數(shù):
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
函數(shù)獲取關聯(lián)屬性,其實就是緩存的代理對象 - 如果沒有值就執(zhí)行
createProxy
函數(shù)客冈,其實就是從DelegateProxyFactory
中取出注冊的生成Rx代理對象的閉包執(zhí)行旭从,進而生成Rx代理對象 - 獲取參數(shù)
ParentObject
的代理對象 - 如果代理對象和Rx代理對象不是同一個對象,那么將代理對象賦值給Rx代理對象的
forwardToDelegate
屬性场仲,將Rx代理對象作為參數(shù)ParentObject
真正的代理對象 - 返回Rx代理對象
總結
羅里吧嗦的分析這么久的代碼和悦,感覺調(diào)理不是很清楚,最后總結下渠缕,Rx
中代理的實現(xiàn)過程鸽素,就以UIScrollViewDelegate
協(xié)議的Rx
實現(xiàn)為例。
首先構建類RxScrollViewDelegateProxy
繼承DelegateProxy
基類亦鳞,同時遵守DelegateProxyType
馍忽、UIScrollViewDelegate
協(xié)議協(xié)議。在RxScrollViewDelegateProxy
中實現(xiàn)registerKnownImplementations
函數(shù)燕差,為遵守UIScrollViewDelegate
協(xié)議的對象注冊一個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
函數(shù)把UIScrollViewDelegate
協(xié)議的子協(xié)議的Rx代理對象的生成閉包一并注冊了遭笋。
DelegateProxyType
協(xié)議定義的下面只讀屬性在DelegateProxyType
擴展中已經(jīng)實現(xiàn),所以不需要不實現(xiàn):
extension DelegateProxyType { UnsafeRawPointer {
let delegateIdentifier = ObjectIdentifier(Delegate.self)
let integerIdentifier = Int(bitPattern: delegateIdentifier)
return UnsafeRawPointer(bitPattern: integerIdentifier)!
}
}
DelegateProxyType
協(xié)議定義的下面兩個函數(shù)在DelegateProxyType
擴展中已經(jīng)實現(xiàn):
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
協(xié)議定義的兩個函數(shù)雖然在DelegateProxyType
擴展中已經(jīng)實現(xiàn)但是需要滿足兩個條件:
- 持有Rx代理對象的類必須遵守
HasDelegate
協(xié)議 -
Self.Delegate
的類型和持有Rx代理對象的類的Delegate
類型必須相同
所以擴展UIScrollView
類徒探,讓其準守HasDelegate
協(xié)議并且讓Delegate
類型和Rx代理對象的類的Delegate
類型必須相同:
extension UIScrollView: HasDelegate {
public typealias Delegate = UIScrollViewDelegate
}
DelegateProxyType
協(xié)議定義的下面兩個函數(shù)在Rx代理基類DelegateProxy
中已經(jīng)實現(xiàn)瓦呼,也不需要再實現(xiàn)了:
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()
}
協(xié)議函數(shù)的Observeble序列實現(xiàn)
有兩種方法可以將協(xié)議中的函數(shù)實現(xiàn)為Observeble序列
Subject方式
這種方式需要在RxScrollViewDelegateProxy
類中,定義對應的UIScrollViewDelegate
協(xié)議中函數(shù)對應的Subject
测暗,并且實現(xiàn)UIScrollViewDelegate
協(xié)議的函數(shù)央串,在協(xié)議的函數(shù)中調(diào)用Subject
的on
操作來發(fā)射元素:
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
協(xié)議允許使用正常的delegates
和Rx觀察序列磨澡,因為RxScrollViewDelegateProxy.proxy(for: base)
中的proxy
操作會將正常的代理對象存儲到Rx代理對象的forwardToDelegate
屬性中,所以在協(xié)議函數(shù)的實現(xiàn)中調(diào)一下forwardToDelegate
對象的協(xié)議函數(shù)蹋辅,達到對正常代理對象的支持(可以參看上面相應的代碼分析)钱贯。
使用RxScrollViewDelegateProxy.proxy(for: base)
提供一個Rx代理對象,為了方便一般都是封裝到一個Base
為UIScrollView
類的Reactive
擴展中侦另,最后拿到相應的Subject
將其轉(zhuǎn)化為Observeble
序列即可:
public var didScroll: ControlEvent<Void> {
let source = RxScrollViewDelegateProxy.proxy(for: base).contentOffsetPublishSubject
return ControlEvent(events: source)
}
消息轉(zhuǎn)發(fā)方式
消息轉(zhuǎn)發(fā)方式不需要實現(xiàn)UIScrollViewDelegate
協(xié)議中函數(shù)秩命,因為沒有實現(xiàn),所以會走基類_RXDelegateProxy
的消息轉(zhuǎn)發(fā)方法forwardInvocation:
(可參看前面相應的代碼分析)褒傅,主要做了如下三件事:
- 執(zhí)行
_sentMessage:withArguments:
方法 - 將未知消息轉(zhuǎn)發(fā)給
_forwardToDelegate
屬性對象 - 執(zhí)行
_methodInvoked:withArguments:
方法
_sentMessage:withArguments:
和_methodInvoked:withArguments:
方法在基類DelegateProxy
中都已實現(xiàn)(可以參看上面相應的代碼分析)弃锐,主要就是根據(jù)selector
獲取相應的MessageDispatcher
(可以參看上面相應的代碼分析)對象執(zhí)行on
操作發(fā)射元素。將未知消息轉(zhuǎn)發(fā)給_forwardToDelegate
屬性對象是為了對正常代理對象的支持殿托。
基類_RXDelegateProxy
暴露sentMessage
和methodInvoked
函數(shù)(可以參看上面相應的代碼分析)根據(jù)selector
構建相應的MessageDispatcher
對象霹菊,并轉(zhuǎn)化為Observeble
序列。
綜上所述支竹,所以直接執(zhí)行Rx代理對象的sentMessage
和methodInvoked
函數(shù)就可以獲得相應的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)
}
}