多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…

欢迎关注公众号:

相关文章
相关标签/搜索