iOS 代理实现一对多的通知

由于通知的一对多实现会产生内存泄漏、耦合关系太离散等一系列问题,有了想用代理实现一对多的方式通知。
需求:当多个类都服从了某个协议并且这些类实现了协议中同一个方法时,触发其中一个代理,所有类都将触发该代理方法。
思路:创建该代理的管理类,用于记录实现该类的target和实现消息转发。

// 把目标类添加到管理类里面
- (void)addTarget:(id)target protcol:(id)protocol {
    
    if (![self.refTargets.allKeys containsObject:protocol]) {
        NSPointerArray *targets = [NSPointerArray weakObjectsPointerArray];
        [targets addPointer:(__bridge void * _Nullable)(target)];
        [self.refTargets setObject:targets forKey:protocol];
    }
    else {
        NSPointerArray *targets = [self.refTargets objectForKey:protocol];
        if ([targets.allObjects containsObject:target]) {
            return;
        }
        [targets addPointer:(__bridge void * _Nullable)(target)];
    }
}


// 方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *sig = [super methodSignatureForSelector:aSelector];
    if (!sig) {
        for (id key in self.refTargets.allKeys) {
            NSPointerArray *targets = [self.refTargets objectForKey:key];
            for (id obj in targets) {
                if ((sig = [obj methodSignatureForSelector:aSelector])) {
                    break;
                }
            }
        }
    }
    return sig;
}

// 方法转发
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    for (NSString* key in self.refTargets.allKeys) {
        NSPointerArray *targets = [self.refTargets objectForKey:key];
        const char *name = [key UTF8String];
        Protocol *protocol = objc_getProtocol(name);
        NSAssert(protocol!=nil, @"不存在的协议");
        struct objc_method_description protocol_method_description =  protocol_getMethodDescription(protocol, anInvocation.selector, YES, YES);
        if (protocol_method_description.name!=nil) {
            for (id obj in targets) {
                if ([obj respondsToSelector:anInvocation.selector]) {
                    [anInvocation invokeWithTarget:obj];
                }
            }
        }
    }
}


// 移除某个目标类
- (void)removeProtocol:(id)protocol{
    if ([self.refTargets.allKeys containsObject:protocol]) {
        [_refTargets removeObjectForKey:protocol];
    }
}

// 移除所有目标类
- (void)removeAll{
    [self.refTargets removeAllObjects];
}

// 判段目标类否是实现该协议
- (BOOL)respondsToSelector:(SEL)aSelector {
    if ([super respondsToSelector:aSelector]) {
        return YES;
    }
    
    for (id key in self.refTargets.allKeys) {
        NSPointerArray *targets = [self.refTargets objectForKey:key];
        for (id obj  in targets) {
            if ([obj respondsToSelector:aSelector]) {
                return YES;
            }
        }
    }
    return NO;
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容