iOS开发之-NSInvocation

简介

Objective-C 是动态语言,所有的消息都是在 Runtime 进行派发的。

最底层的转发函数为objc_msgSend。

使用 performSelector 可以给对象发送消息,但是其有几个短板

  • 在 ARC 场景下 performSelector 可能会造成内存泄漏
  • performSelector 至多接收 2 个参数,如果参数多余 2 个,我们就无法使用 performSelector 来向对象发送消息了。
  • performSelector 限制参数类型为 id,以标量数据(int double NSInteger 等)为参数的方法使用 performSelector 调用会出现各种各样诡异的问题

NSInvocation 是苹果工程师们提供的一个高层的消息转发系统。它是一个命令对象,是一个消息调用类,可以给任何 Objective-C 对象类型发送消息。

NSInvocation 包含了所有OC消息的成分:target、selector、参数、返回值等。NSInvocation可以将消息转换成一个对象,消息的每一个参数能够直接设定,而且当一个NSInvocation对象调度时返回值是可以自己设定的。一个NSInvocation对象能够重复的调度不同的目标(target),而且它的selector也能够设置为另外一个方法签名。

NSInvocation 的使用

使用步骤:

创建方法创建签名对象NSMethodSignature
根据签名对象创建调用NSInvocation
设置调用对象相关信息
调用方法
获取返回值
无参数、无返回值

无参数、无返回值 的 对应代码为:

- (void)startTest_Imple
{
// 获取方法签名
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:@selector(startTest)];
// 生成调用对象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
// 设置target
invocation.target = self;
// 设置方法实现
invocation.selector = @selector(startTest);
// 调用
[invocation invoke];
}

- (void)startTest
{
NSLog(@"无参数、无返回值:startTest_1");
}

两个个参数、有返回值的代码为:

- (void)startTest_Imple_3
{
// 获取方法签名
NSMethodSignature *signature = [ViewController instanceMethodSignatureForSelector:@selector(startTest_3:text1:)];
// 生成调用对象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
// 设置target
invocation.target = self;
// 设置方法实现
invocation.selector = @selector(startTest_3:text1:);
// 设置参数,参数必须从2开始,第一个第二个参数为target和selector
NSString *argument = @"参数1";
NSString *argument1 = @"参数2";
[invocation setArgument:&argument atIndex:2];
[invocation setArgument:&argument1 atIndex:3];
// 调用
[invocation invoke];
NSString *returnValue = nil;
[invocation getReturnValue:&returnValue];
NSLog(@"返回值:%@",returnValue);
}
- (NSString *)startTest_3:(NSString *)text text1:(NSString *)text1
{
NSLog(@"参数%@--%@,无返回值:startTest_1",text,text1);
return @"返回值";
}

具体实例,下面用NSInvocation方式来调用sendMessageWithNumber方法。

- (void)viewDidLoad {
[super viewDidLoad];
//NSInvocation;用来包装方法和对应的对象,它可以存储方法的名称,对应的对象,对应的参数,
/*
NSMethodSignature:签名:再创建NSMethodSignature的时候,必须传递一个签名对象,签名对象的作用:用于获取参数的个数和方法的返回值

*/
//创建签名对象的时候不是使用NSMethodSignature这个类创建,而是方法属于谁就用谁来创建
NSMethodSignature*signature = [ViewController instanceMethodSignatureForSelector:@selector(sendMessageWithNumber:WithContent:)];

//1、创建NSInvocation对象
NSInvocation*invocation = [NSInvocation invocationWithMethodSignature:signature];

invocation.target = self;

//invocation中的方法必须和签名中的方法一致。
invocation.selector = @selector(sendMessageWithNumber:WithContent:);

/*第一个参数:需要给指定方法传递的值
第一个参数需要接收一个指针,也就是传递值的时候需要传递地址*/
//第二个参数:需要给指定方法的第几个参数传值
NSString*number = @"1111";

//注意:设置参数的索引时不能从0开始,因为0已经被self占用,1已经被_cmd占用
[invocation setArgument:&number atIndex:2];

NSString*number2 = @"啊啊啊";

[invocation setArgument:&number2 atIndex:3];

//2、调用NSInvocation对象的invoke方法
//只要调用invocation的invoke方法,就代表需要执行NSInvocation对象中制定对象的指定方法,并且传递指定的参数
[invocation invoke];
}
- (void)sendMessageWithNumber:(NSString*)number WithContent:(NSString*)content{
NSLog(@"电话号%@,内容%@",number,content);

}
iOS开发之-NSInvocation


分享到:


相關文章: