1.NSInvocation的作用
封装了方法调用对象、方法选择器、参数、返回值等,可以给对象发送一个参数大于两个的消息
2. 优势
在iOS中可以直接给某个对象发送消息的方法有两种
- performSelector 这种类型的方法最多只能有两个参数
- NSInvocation 它可以设置多个参数
3. NSInvocation使用方式
- 通过NSObject类生成方法签名
- 通过方法签名生成NSInvaocation
- 设置方法调用者
- 设置方法选择器
- 设置参数
- 如果有返回值,获取返回值
代码演示:
- (void)test:(NSString *)name age:(NSString *)age sex:(NSString *)sex{
NSLog(@"%@-%@-%@",name,age,sex);
}
- (void)viewDidLoad {
[super viewDidLoad];
// 1.通过方法调用者创建方法签名:这个方法是NSObject的方法
NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:@selector(test:age:sex:)];
// 2.生成NSInvocation对象
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
// 3.设置方法调用者
invocation.target = self;
// 4.设置方法选择器
invocation.selector = @selector(test:age:sex:);
// 5.设置参数
NSString *name = @"张三";
NSString *age = @"11";
NSString *sex = @"男";
// 设置的参数从2开始,因为默认有两个参数 self _cmd
[invocation setArgument:&name atIndex:2];
[invocation setArgument:&age atIndex:3];
[invocation setArgument:&sex atIndex:4];
// 6.执行方法
[invocation invoke];
// 7.判断方法签名 判断是否有返回值
const char *sigretun = sig.methodReturnType; //方法签名的返回值
NSUInteger siglength = sig.methodReturnLength; //方法签名返回值长度; 如果是字符串返回8,数字返回4,没有返回值返回0;
if (siglength !=0) { //有返回值
if (strcmp(sigretun, "@") == 0) {
NSString *returnStr;
[invocation getReturnValue:&returnStr];
NSLog(@"字符串返回值:%@",returnStr);
}else if (strcmp(sigretun, "i")){
int a = 0;
[invocation setReturnValue:&a];
NSLog(@"数字返回值:%zd",a);
}
}else{ //没有返回值
NSLog(@"没有返回值");
}
}
performSelctor就不提供代码演示了。
4. NSInvocation使用场景
在与js 交互中,点击webview 上某个按钮,获取网页上的一些跳转链接;例如:ml://sendMessage_name_age_sex?name=zhangsan&age=20&sex=boy;获取链接之后,再在oc 中进行处理,获得方法名字符换(sendMessage:name:age:sex),并提取相应的参数值放到数组里面;将方法名字符串和参数一起放到NSInvocation中进行处理,进而调用oc 中
-(void)sendMessage:(NSString *)name age:(NSSring*)age sex:(NSString*)sex;
5. 常见方法及属性
//保留参数,它会将所有参数和self 都retain 一遍
-(void)retainArguments;
//判断参数是否存在,调用retainArguments之前,值为NO,调用之后值为YES
@property(readonly)Bool argumentsRetained;
6.扩展
#import "NSObject+Exception.h"
@implementation NSObject (Exception)
-(id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects{
//生成方法签名
NSMethodSignature *sig = [NSMethodSignature methodSignatureForSelector:aSelector];
if (sig == nil) { //如果方法签名不存在抛出异常
[NSException raise:@"exceptionName" format:@"%@not found method",NSStringFromSelector(aSelector)];
}
//生成invocation
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
invocation.target = self;// 设置调用对象
invocation.selector = aSelector;//设置方法选择器
NSInteger num = sig.numberOfArguments -2; //传递进来的参数个数
NSInteger min = MAX(num, objects.count); //取得参数的数量;
for (int i = 0; i< min; i++) {
id obj = objects[i];
if ([obj isKindOfClass:[NSNull class]]) continue;
//设置参数
[invocation setArgument:&obj atIndex:i+2];
}
//调用方法
[invocation invoke];
//获得返回值
id retrunvalue = nil;
if (sig.methodReturnLength !=0) { //如果有返回值的话,获取返回值
[invocation getReturnValue:&retrunvalue];
}
return retrunvalue;
}
@end
网友评论