iOS开发中利用消息转发实现多重代理
2017-03-21 本文已影响771人
JimWithJiang
在iOS开发中,我们经常碰到修改完某处,需要在多个页面进行更新,或者是刷新完数据,要在多个页面进行同步,比如聊天时,给对方昵称添加个备注,需要在资料页,聊天页,聊天列表页等同步进行更新,这个时候如果想用代理实现怎么办呢?其实我们可以利用消息转发来实现多重代理,以满足上面的业务需求。
先补充点东西,在OC中调用一个方法,此处以实例方法为例,如
[p eat];
当这个eat方法不存在时,会到这里
+ (BOOL)resolveInstanceMethod:(SEL)sel{
return [super resolveInstanceMethod:sel];
}
如果不在上面增加这个eat方法,会到这里
- (id)forwardingTargetForSelector:(SEL)aSelector{
return [super forwardingTargetForSelector:aSelector];
}
同样如果不在上面那个方法进行转发到其它对象处理eat方法,会到这里
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
return [super methodSignatureForSelector:aSelector];
}
此时不进行处理,程序也就崩了'NSInvalidArgumentException', reason: '-[Person eat]: unrecognized selector sent to instance。说了这么多,现在回到正题,我们可以这么处理,
在下面方法中返回一个方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
并在下面方法中实现消息转发,发给每个需要实现这个方法的对象
- (void)forwardInvocation:(NSInvocation *)invocation
过程如下:
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
NSMethodSignature* signature = [super methodSignatureForSelector:selector];
if (signature)
return signature;
[_delegates compact];
if (self.silentWhenEmpty && _delegates.count == 0) {
return [self methodSignatureForSelector:@selector(description)];
}
for (id delegate in _delegates) {//存储了各个对象的代理
if (!delegate)
continue;
signature = [delegate methodSignatureForSelector:selector];
if (signature)
break;
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL selector = [invocation selector];
BOOL responded = NO;
for (id delegate in _delegates) {//遍历存储给个对象的代理,发送给每个要实现代理方法的对象
if (delegate && [delegate respondsToSelector:selector]) {
[invocation invokeWithTarget:delegate];
responded = YES;
}
}
if (!responded && !self.silentWhenEmpty)
[self doesNotRecognizeSelector:selector];
}
接下来通过一个demo 来具体看下。demo中要实现的功能是在当item1中点击传递消息按钮,item1,item2,item3中对应的控制器打印出收到了这个点击消息(3个控制器都已经加载过页面)。
首先分别在三个控制器中
[[Manager shareManager] addDelegate:self];//Manager是一个管理者,在里面实现了代理的添加与删除,具体实现见demo。
然后点击时调用Manager中的处理方法
[[Manager shareManager] reciveBottonClick:sender];//放到Manager去实现
接下去就是在Manager中处理业务与通知各个对象
- (void)reciveBottonClick:(UIButton *)button{
...... //这里进行业务处理
[_multiDelegate manager:self didBottonClick:button];//处理完后通知各个对象实现代理方法
}
上面最后一步的
[_multiDelegate manager:self didBottonClick:button];
就是通过刚才所说的找不到方法时返回一个方法签名,再转发消息给多个对象进行实现。此时控制台打印出
2017-03-20 19:35:11.659 MultiDelegateDemo[81609:15766652] 我是item1,接受到了按钮点击的消息,按钮地址是0x7f95eb101490
2017-03-20 19:35:11.659 MultiDelegateDemo[81609:15766652] 我是item2,接受到了按钮点击的消息,按钮地址是0x7f95eb101490
2017-03-20 19:35:11.659 MultiDelegateDemo[81609:15766652] 我是item3,接受到了按钮点击的消息,按钮地址是0x7f95eb101490
每个控制器都实现了
- (void)manager:Manager *)manager didBottonClick:(UIButton *)button{
NSLog(@"我是item x,接受到了按钮点击的消息,按钮地址是%p",button);
}
最后附上demo地址https://github.com/JimWithJiang/MultiDelegateDemo,里面已经封装好了实现转发的类,只需要在Manager中添加自己需要的业务。
本文难免有纰漏和错误,如有发现敬请指正,谢谢!