前言
最近在看Effective Objective-C 2.0這本書(shū),在介紹消息轉(zhuǎn)發(fā)機(jī)制這部分的時(shí)候,遇到了NSInvocation這個(gè)類。
蘋果給的官方解釋是:NSInvocation作為對(duì)象呈現(xiàn)的Objective-C消息。
An Objective-C message rendered as an object.
NSInvocation objects are used to store and forward messages between objects and between applications, primarily by NSTimer objects and the distributed objects system. An NSInvocation
object contains all the elements of an Objective-C message: a target, a selector, arguments, and the return value. Each of these elements can be set directly, and the return value is set automatically when the NSInvocation object is dispatched.
一個(gè)NSInvocation對(duì)象包含一個(gè)Objective-C消息的所有元素:target,selector,argument和return value??梢灾苯釉O(shè)置每個(gè)元素,并且在NSInvocation分派對(duì)象時(shí)自動(dòng)設(shè)置返回值。
所謂的方法簽名,即方法所對(duì)應(yīng)的返回值類型和參數(shù)類型。當(dāng)NSInvocation被調(diào)用,它會(huì)在運(yùn)行時(shí)通過(guò)目標(biāo)對(duì)象去尋找對(duì)應(yīng)的方法,從而確保唯一性,可以用[receiver message]來(lái)解釋。實(shí)際開(kāi)發(fā)過(guò)程中直接創(chuàng)建NSInvocation的情況不多見(jiàn),這些事情通常交給系統(tǒng)來(lái)做。比如bang的JSPatch中arm64方法替換的實(shí)現(xiàn)就是利用runtime消息轉(zhuǎn)發(fā)最后一步中的NSInvocation實(shí)現(xiàn)的。
NSInvocation的一般用法
以下面字符串拼接為例,我們來(lái)嘗試將該方法的調(diào)用轉(zhuǎn)換為NSInvocation的消息轉(zhuǎn)發(fā)。
NSString *string = @"Hello";
NSString *addString = [string stringByAppendingString:@" World!"];
用NSInvocation轉(zhuǎn)換后:
NSString *string = @"Hello";
void* addString;
NSString* stringToAppend = @" World!";
//invocationWithMethodSignature: 使用給定方法簽名來(lái)構(gòu)建消息的對(duì)象。
NSMethodSignature *signature = [string methodSignatureForSelector:@selector(stringByAppendingString:)];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
//設(shè)置target
invocation.target = string;
invocation.selector = @selector(stringByAppendingString:);
//設(shè)置參數(shù)即上面對(duì)應(yīng)的World!字符串,index為2 是因?yàn)?、1兩個(gè)參數(shù)已經(jīng)被target和selector占用
[invocation setArgument:&stringToAppend atIndex:2];
//執(zhí)行制定對(duì)象的指定方法,并且傳遞指定的參數(shù)
[invocation invoke];
//得到返回值 并賦值addString
if (signature.methodReturnLength > 0) {
[invocation getReturnValue:&addString];
NSString *str = (__bridge NSString *)addString;
NSLog(@"%@",str);
}
一般是通過(guò)NSInvocation進(jìn)行消息轉(zhuǎn)發(fā)來(lái)實(shí)現(xiàn)未定義的方法,通過(guò)runtime來(lái)實(shí)現(xiàn)消息的動(dòng)態(tài)發(fā)送。
之后對(duì)NSInvocation的研究再在下面補(bǔ)充!