[iOS 知识总结五] 多播委托
2017-07-21 本文已影响89人
pengxuyuan
需求场景
- 假如说一个页面中有 5 个 Label ( A , B , C ,D ,E),页面初始化的时候要发一个请求信息的请求,请求回调成功之后,我们要让 A 显示昵称,B 显示性别,C 显示年龄
解决方法
方法一
我们可以在回调成功之后,拿到这 3 个 Label ,然后去对他进行赋值
这个办法当然可以,现在是 3 个 Label ,还比较少,如果以后改成 7 个,8 个,或者更多?我们要写多少代码?或者变成了更复杂的控件?这是灾难性的,不太可取
方法二
利用通知。我们可以在 Label 初始化的时候加个监听,请求回调成功之后发通知,Label 接收到之后做各自的处理
通知只要有地方监听了就可以收到,虽然是简单很多,但是有时候会超出我们的预期,比如我们只想让三个 Label 进行事件处理,但是其他地方也监听了,那么,其他地方也会进行事件处理,我们不能对其进行约束。这样子,代码越写越多,可能会导致一些乱七八糟的问题
而且 iOS 的通知简直不要太麻烦,要注册,还得在适当的时候从消息中心移除,如果新加一个控件简直写到心累。。。。
方法三
能不能有这样一种实现,我们封装一个东西出来,在回调成功之后,只调用一个方法,就可以分发到我们想处理的控件中,让它们自己进行事件处理?
多播委托就是这种模式,下面我们就看一下多播委托的实现原理
如何实现多播委托
实现一对多代理主要要实现以下两点:
- 我们需要知道有哪些对象需要进行监听,这里我们用一个数组来保存
- 然后对于代理的消息需要一一转发到这个数组里面的对象中去
这里需要用到类似蹦床模式的思想:一个类不做任何事情,只是负责转发消息
转发消息我们可以利用Objective-C 中的消息转发机制来转发,代码示例如下:
//1.创建一个中间类来保存需要转发的对象们&转发消息
/*
PXYMulticastDelegate 这个类我继承自NSProxy,因为NSProxy 这类就是专门用来转发消息的,比较恰当
这里提供几个方法,增加需要监听的对象,并且可以设置回调的队列
*/
@interface PXYMulticastDelegate : NSProxy
- (instancetype)init;
- (void)addDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate delegateQueue:(dispatch_queue_t)delegateQueue;
- (void)removeDelegate:(id)delegate;
- (void)removeAllDelegate;
@end
/*
PXYMulticastDelegate 具体核心方法
*/
#pragma mark - 蹦床模式 消息转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
for (PXYMulticastDelegateNode *node in _observers) {
id nodeDelegate = node.delegate;
NSMethodSignature *result = [nodeDelegate methodSignatureForSelector:aSelector];
if (result != nil) {
return result;
}
}
// return [super methodSignatureForSelector:aSelector];
return [[self class] methodSignatureForSelector:@selector(doNothing)];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
for (PXYMulticastDelegateNode *node in _observers) {
id nodeDelegate = node.delegate;
dispatch_queue_t delegateQueue = node.delegateQueue;
if ([nodeDelegate respondsToSelector:selector]) {
dispatch_async(delegateQueue, ^{
[anInvocation invokeWithTarget:nodeDelegate];
});
}
}
}
//使用
_multicastDelegate = (PXYMulticastDelegate<ViewControllerDelegate> *)[[PXYMulticastDelegate alloc] init];
[_multicastDelegate addDelegate:self delegateQueue:nil];
[_multicastDelegate addDelegate:_test2 delegateQueue:nil];
self.delegate = _multicastDelegate;
[self.delegate test];
设计思想:
- 创建中间类来管理
- 有个数组来保存需要监听的对象
- 中间类收到消息然后逐一转发给数组中的对象
这里就是多播委托了,平时需要用到多播委托,如果不想自己写的话,可以使用GCDMulticastDelagate 这个帮助类