在iOS開(kāi)發(fā)中搭综,我們經(jīng)常碰到修改完某處,需要在多個(gè)頁(yè)面進(jìn)行更新划栓,或者是刷新完數(shù)據(jù)兑巾,要在多個(gè)頁(yè)面進(jìn)行同步,比如聊天時(shí)忠荞,給對(duì)方昵稱(chēng)添加個(gè)備注蒋歌,需要在資料頁(yè),聊天頁(yè)委煤,聊天列表頁(yè)等同步進(jìn)行更新堂油,這個(gè)時(shí)候如果想用代理實(shí)現(xiàn)怎么辦呢?其實(shí)我們可以利用消息轉(zhuǎn)發(fā)來(lái)實(shí)現(xiàn)多重代理碧绞,以滿(mǎn)足上面的業(yè)務(wù)需求府框。
先補(bǔ)充點(diǎn)東西,在OC中調(diào)用一個(gè)方法讥邻,此處以實(shí)例方法為例迫靖,如
[p eat];
當(dāng)這個(gè)eat方法不存在時(shí),會(huì)到這里
+ (BOOL)resolveInstanceMethod:(SEL)sel{
return [super resolveInstanceMethod:sel];
}
如果不在上面增加這個(gè)eat方法计维,會(huì)到這里
- (id)forwardingTargetForSelector:(SEL)aSelector{
return [super forwardingTargetForSelector:aSelector];
}
同樣如果不在上面那個(gè)方法進(jìn)行轉(zhuǎn)發(fā)到其它對(duì)象處理eat方法袜香,會(huì)到這里
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
return [super methodSignatureForSelector:aSelector];
}
此時(shí)不進(jìn)行處理,程序也就崩了'NSInvalidArgumentException', reason: '-[Person eat]: unrecognized selector sent to instance鲫惶。說(shuō)了這么多,現(xiàn)在回到正題实抡,我們可以這么處理,
在下面方法中返回一個(gè)方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
并在下面方法中實(shí)現(xiàn)消息轉(zhuǎn)發(fā)欠母,發(fā)給每個(gè)需要實(shí)現(xiàn)這個(gè)方法的對(duì)象
- (void)forwardInvocation:(NSInvocation *)invocation
過(guò)程如下:
- (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) {//存儲(chǔ)了各個(gè)對(duì)象的代理
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) {//遍歷存儲(chǔ)給個(gè)對(duì)象的代理,發(fā)送給每個(gè)要實(shí)現(xiàn)代理方法的對(duì)象
if (delegate && [delegate respondsToSelector:selector]) {
[invocation invokeWithTarget:delegate];
responded = YES;
}
}
if (!responded && !self.silentWhenEmpty)
[self doesNotRecognizeSelector:selector];
}
接下來(lái)通過(guò)一個(gè)demo 來(lái)具體看下吆寨。demo中要實(shí)現(xiàn)的功能是在當(dāng)item1中點(diǎn)擊傳遞消息按鈕赏淌,item1,item2啄清,item3中對(duì)應(yīng)的控制器打印出收到了這個(gè)點(diǎn)擊消息(3個(gè)控制器都已經(jīng)加載過(guò)頁(yè)面)六水。
首先分別在三個(gè)控制器中
[[Manager shareManager] addDelegate:self];//Manager是一個(gè)管理者,在里面實(shí)現(xiàn)了代理的添加與刪除辣卒,具體實(shí)現(xiàn)見(jiàn)demo掷贾。
然后點(diǎn)擊時(shí)調(diào)用Manager中的處理方法
[[Manager shareManager] reciveBottonClick:sender];//放到Manager去實(shí)現(xiàn)
接下去就是在Manager中處理業(yè)務(wù)與通知各個(gè)對(duì)象
- (void)reciveBottonClick:(UIButton *)button{
...... //這里進(jìn)行業(yè)務(wù)處理
[_multiDelegate manager:self didBottonClick:button];//處理完后通知各個(gè)對(duì)象實(shí)現(xiàn)代理方法
}
上面最后一步的
[_multiDelegate manager:self didBottonClick:button];
就是通過(guò)剛才所說(shuō)的找不到方法時(shí)返回一個(gè)方法簽名,再轉(zhuǎn)發(fā)消息給多個(gè)對(duì)象進(jìn)行實(shí)現(xiàn)荣茫。此時(shí)控制臺(tái)打印出
2017-03-20 19:35:11.659 MultiDelegateDemo[81609:15766652] 我是item1想帅,接受到了按鈕點(diǎn)擊的消息,按鈕地址是0x7f95eb101490
2017-03-20 19:35:11.659 MultiDelegateDemo[81609:15766652] 我是item2啡莉,接受到了按鈕點(diǎn)擊的消息港准,按鈕地址是0x7f95eb101490
2017-03-20 19:35:11.659 MultiDelegateDemo[81609:15766652] 我是item3旨剥,接受到了按鈕點(diǎn)擊的消息,按鈕地址是0x7f95eb101490
每個(gè)控制器都實(shí)現(xiàn)了
- (void)manager:Manager *)manager didBottonClick:(UIButton *)button{
NSLog(@"我是item x浅缸,接受到了按鈕點(diǎn)擊的消息轨帜,按鈕地址是%p",button);
}
最后附上demo地址https://github.com/JimWithJiang/MultiDelegateDemo,里面已經(jīng)封裝好了實(shí)現(xiàn)轉(zhuǎn)發(fā)的類(lèi),只需要在Manager中添加自己需要的業(yè)務(wù)衩椒。
本文難免有紕漏和錯(cuò)誤阵谚,如有發(fā)現(xiàn)敬請(qǐng)指正,謝謝烟具!