iOS开发中利用消息转发实现多重代理

在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个控制器都已经加载过页面)。

demo1.png

首先分别在三个控制器中

[[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中添加自己需要的业务。

本文难免有纰漏和错误,如有发现敬请指正,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,349评论 25 708
  • 点击查看原文 Web SDK 开发手册 SDK 概述 网易云信 SDK 为 Web 应用提供一个完善的 IM 系统...
    layjoy阅读 13,934评论 0 15
  • 清河水之波,打水漂染了粉,蹦蹦跳跳,甚可爱。花儿是一阵风,打我心里飘过,挽在了伊的发丝间,万般美。树上的雀儿不见影...
    司才林阅读 208评论 7 7
  • 羽生怎么也没想到,结弦的报复会来得如此突然。那天到了羽田之后马不停蹄的赶去参加归国采访,虽然这一次世锦赛整个队伍取...
    糖水不等式阅读 352评论 0 1
  • 文/青藜 在桂花开始飘香的季节,我来到名叫仰阿莎故乡的城市开始新的征程。他们说我是幸运的,因为我暂时不用到离家更偏...
    Only青藜阅读 325评论 0 2