前言
最近在看Effective Objective-C 2.0这本书,在介绍消息转发机制这部分的时候,遇到了NSInvocation这个类。
苹果给的官方解释是:NSInvocation作为对象呈现的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.
一个NSInvocation对象包含一个Objective-C消息的所有元素:target,selector,argument和return value。可以直接设置每个元素,并且在NSInvocation分派对象时自动设置返回值。
所谓的方法签名,即方法所对应的返回值类型和参数类型。当NSInvocation被调用,它会在运行时通过目标对象去寻找对应的方法,从而确保唯一性,可以用[receiver message]来解释。实际开发过程中直接创建NSInvocation的情况不多见,这些事情通常交给系统来做。比如bang的JSPatch中arm64方法替换的实现就是利用runtime消息转发最后一步中的NSInvocation实现的。
NSInvocation的一般用法
以下面字符串拼接为例,我们来尝试将该方法的调用转换为NSInvocation的消息转发。
NSString *string = @"Hello";
NSString *addString = [string stringByAppendingString:@" World!"];
用NSInvocation转换后:
NSString *string = @"Hello";
void* addString;
NSString* stringToAppend = @" World!";
//invocationWithMethodSignature: 使用给定方法签名来构建消息的对象。
NSMethodSignature *signature = [string methodSignatureForSelector:@selector(stringByAppendingString:)];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
//设置target
invocation.target = string;
invocation.selector = @selector(stringByAppendingString:);
//设置参数即上面对应的World!字符串,index为2 是因为0、1两个参数已经被target和selector占用
[invocation setArgument:&stringToAppend atIndex:2];
//执行制定对象的指定方法,并且传递指定的参数
[invocation invoke];
//得到返回值 并赋值addString
if (signature.methodReturnLength > 0) {
[invocation getReturnValue:&addString];
NSString *str = (__bridge NSString *)addString;
NSLog(@"%@",str);
}
一般是通过NSInvocation进行消息转发来实现未定义的方法,通过runtime来实现消息的动态发送。
之后对NSInvocation的研究再在下面补充!