多delegate使用

多delegate的使用

通常在咱們使用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…

歡迎關注公衆號:

相關文章
相關標籤/搜索