通常在咱們使用delegate都知道,是一對一的關係。在目前的項目中,有這樣一個需求,在服務端收到了一個下發事件,須要在不一樣的頁面,不一樣的VC都收到此事件,並進行相應的處理。固然這個用RAC實現很簡單,可是目前的項目是一個SDK,若是將ReactiveCocoa引入進來,工程會增大不少,這樣明顯是不合理的,這個時候,就想到了多代理這個思路。其實也是從以前寫的proxy代理類的想法而來。node
主要是利用OC的runtime,將一個代理類做爲中間類,當收到服務器下發的通知時,經過調用代理類的方法,在代理類中實現消息轉發機制,將selector轉發給各個代理類。git
仍是看代碼。github
首先,咱們是將各個代理存在中間類中,這樣才能轉發到各個代理。數組
@interface PPSMutableDelegate : NSObject
- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate;
- (void)removeAllDelegates;
@end
複製代碼
在須要監聽的delegate中 經過addDelegate將代理添加進去就行,加入queue的目的是爲了,在某些收到消息的方法中,須要進行一些異步處理。若是要在主線程中處理,直接放dispatch_get_main_queue()就ok服務器
//代理對象和代理隊列持有類
@interface PPSDelegateNode : NSObject
@property (nonatomic, weak) id delegate;
@property (nonatomic, strong) dispatch_queue_t delegateQueue;
- (id)initWithDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
@end
@implementation PPSDelegateNode
- (id)initWithDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue {
self = [super init];
if (self) {
_delegate = delegate;
_delegateQueue = delegateQueue;
}
return self;
}
@end
複製代碼
這就是一個model類,用來存儲一下delegate異步
在具體的PPSMutableDelegate實現中,用了一個NSMutableArray用來儲存delegate 在進行消息轉發時,遍歷數組 轉發出去就行,實現也很簡單async
在實現消息轉發時,主要是經過ui
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
- (void)forwardInvocation:(NSInvocation *)anInvocation;
複製代碼
在實現methodSignatureForSelector:方法時,要注意在這個方法中不能返回nil 不然會崩潰的,因此若是delegate中沒有找到實現,能夠在當前實現一個空的方法atom
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
for (PPSDelegateNode *node in self.delegateNodes) {
id nodeDelegate = node.delegate;
NSMethodSignature *result = [nodeDelegate methodSignatureForSelector:aSelector];
if (result != nil) {
return result;
}
}
return [[self class] instanceMethodSignatureForSelector:@selector(emptyMethod)];
}
複製代碼
實現forwardInvocation:spa
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
BOOL foundNilDelegate = NO;
for (PPSDelegateNode *node in self.delegateNodes) {
id nodeDelegate = node.delegate;
if ([nodeDelegate respondsToSelector:selector]) {
dispatch_async(node.delegateQueue, ^{
[anInvocation invokeWithTarget:nodeDelegate];
});
} else if (nodeDelegate == nil) {
foundNilDelegate = YES;//找到了delegate是空的node 須要移除掉
}
}
if (foundNilDelegate) {
NSMutableIndexSet *indexSet = [[NSMutableIndexSet alloc] init];
NSUInteger i = 0;
for (PPSDelegateNode *node in self.delegateNodes) {
id nodeDelegate = node.delegate;
if (nodeDelegate == nil) {
[indexSet addIndex:i];
}
i++;
}
[self.delegateNodes removeObjectsAtIndexes:indexSet];
}
}
複製代碼
注意 還有一個問題須要注意,要重寫當前中間類的doesNotRecognizeSelector:方法,否則若是調用super的這個方法,會形成崩潰
demo地址:github.com/yangqian111…
歡迎關注公衆號: