前提:
在 iOS中可以直接調(diào)用某個(gè)對(duì)象的消息方式有兩種:
一種是performSelector:withObject对扶;
再一種就是NSInvocation筒溃。
第一種方式比較簡(jiǎn)單踱讨,能完成簡(jiǎn)單的調(diào)用峭梳。但是對(duì)于>2個(gè)的參數(shù)或者有返回值的處理碾篡,那performSelector:withObject就顯得有點(diǎn)有心無(wú)力了虱而,那么在這種情況下,我們就可以使用NSInvocation來(lái)進(jìn)行這些相對(duì)復(fù)雜的操作
NSInvocation的基本使用
方法簽名類
<pre>
// 方法簽名中保存了方法的名稱/參數(shù)/返回值开泽,協(xié)同NSInvocation來(lái)進(jìn)行消息的轉(zhuǎn)發(fā) // 方法簽名一般是用來(lái)設(shè)置參數(shù)和獲取返回值的, 和方法的調(diào)用沒(méi)有太大的關(guān)系 //1牡拇、根據(jù)方法來(lái)初始化 NSMethodSignatureNSMethodSignature *signature = [ViewController instanceMethodSig
</pre>
根據(jù)方法簽名來(lái)創(chuàng)建NSInvocation對(duì)象
<pre>`
// NSInvocation中保存了方法所屬的對(duì)象/方法名稱/參數(shù)/返回值
//其實(shí)NSInvocation就是將一個(gè)方法變成一個(gè)對(duì)象
//2、創(chuàng)建NSInvocation對(duì)象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
//設(shè)置方法調(diào)用者
invocation.target = self;
//注意:這里的方法名一定要與方法簽名類中的方法一致
invocation.selector = @selector(run:);
NSString *way = @"byCar";
//這里的Index要從2開(kāi)始穆律,以為0跟1已經(jīng)被占據(jù)了惠呼,分別是self(target),selector(_cmd)
[invocation setArgument:&way atIndex:2];
//3、調(diào)用invoke方法
[invocation invoke];
//實(shí)現(xiàn)run:方法
- (void)run:(NSString *)method{
}
`</pre>
優(yōu)化
但是上述方法有很多弊端峦耘,首先我們來(lái)一一解決
1剔蹋、如果調(diào)用的方法不存在
<pre>//此時(shí)我們應(yīng)該判斷方法是否存在,如果不存在這拋出異常 if (signature == nil) { //aSelector為傳進(jìn)來(lái)的方法 NSString *info = [NSString stringWithFormat:@"%@方法找不到", NSStringFromSelector(aSelector)]; [NSException raise:@"方法調(diào)用出現(xiàn)異常" format:info, nil]; }
</pre>
2辅髓、方法的參數(shù)個(gè)數(shù)與外界傳進(jìn)來(lái)的參數(shù)數(shù)組元素個(gè)數(shù)不符
<pre>//此處不能通過(guò)遍歷參數(shù)數(shù)組來(lái)設(shè)置參數(shù)泣崩,因?yàn)橥饨鐐鬟M(jìn)來(lái)的參數(shù)個(gè)數(shù)是不可控的 //因此通過(guò)numberOfArguments方法獲取的參數(shù)個(gè)數(shù),是包含self和_cmd的,然后比較方法需要的參數(shù)和外界傳進(jìn)來(lái)的參數(shù)個(gè)數(shù)洛口,并且取它們之間的最小值 NSUInteger argsCount = signature.numberOfArguments - 2; NSUInteger arrCount = objects.count; NSUInteger count = MIN(argsCount, arrCount); for (int i = 0; i < count; i++) { id obj = objects[i]; // 判斷需要設(shè)置的參數(shù)是否是NSNull, 如果是就設(shè)置為nil if ([obj isKindOfClass:[NSNull class]]) { obj = nil; } [invocation setArgument:&obj atIndex:i + 2]; }
</pre>
3矫付、判斷當(dāng)前調(diào)用的方法是否有返回值
<pre>``
//方法一:
id res = nil;
if (signature.methodReturnLength != 0) {//有返回值
//將返回值賦值給res
[invocation getReturnValue:&res];
}
return res;
//方法二:
//可以通過(guò)signature.methodReturnType獲得返回的類型編碼,因此可以推斷返回值的具體類型
</pre>