NSInvocation 理解
1、NSInvocation的作用
封装了 方法调用对象、方法选择器、参数、返回值等,可以给对象发送一个参数大于两个的消息
2、优势
在 iOS 中可以直接调用某个对象的消息的方法有两种
1:performSelector: withObject: 这种类型的方法最多只能有两个参数
2:NSInvocation,它可以设置多个参数;
3、使用方式
- 通过NSObject 类生成方法签名
- 通过方法签名生成 NSInvocation
- 设置方法调用者
- 设置方法选择器
- 设置参数
- 如果有返回值,获取返回值
invocation代码演示
1 // 三个参数的方法 2 - (void)red:(NSString *)r green:(NSString *)g blue:(NSString *)b { 3 NSLog(@"%@-%@-%@",r,g,b); 4 } 5 6 - (void)invocationInstance { 7 // 1.通过方法调用者创建方法签名;此方法是NSObject 的方法 8 NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:@selector(red:green:blue:)]; 9 // 2.通过方法签名 生成NSInvocation 10 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; 11 // 3.对invocation设置 方法调用者 12 invocation.target = self; 13 // 4.对invocation设置 方法选择器 14 invocation.selector = @selector(red:green:blue:); 15 // 5.对invocation设置 参数 16 NSString *r = @"ff"; 17 NSString *g = @"aa"; 18 NSString *b = @"33"; 19 // 注意:设置的参数必须从2开始;因为0和1 已经被self ,_cmd 给占用了 20 [invocation setArgument:&r atIndex:2]; 21 [invocation setArgument:&g atIndex:3]; 22 [invocation setArgument:&b atIndex:4]; 23 // 6.执行invocation 24 [invocation invoke]; 25 // 7.判断 方法签名 判断是否有返回值 26 const char *sigretun = sig.methodReturnType; //方法签名的返回值 27 NSUInteger siglength = sig.methodReturnLength; //方法签名返回值长度; 如果是字符串返回8,数字返回4,没有返回值返回0; 28 if (siglength !=0) { //有返回值 29 if (strcmp(sigretun, "@") == 0) { 30 NSString *returnStr; 31 [invocation getReturnValue:&returnStr]; 32 NSLog(@"字符串返回值:%@",returnStr); 33 } else if (strcmp(sigretun, "i")) { 34 int a = 0; 35 [invocation setReturnValue:&a]; 36 NSLog(@"数字返回值:%d", a); 37 } 38 } else { //没有返回值 39 NSLog(@"没有返回值"); 40 } 41 42 // 8.常用方法 43 NSUInteger argumentNum = sig.numberOfArguments; 44 NSLog(@"%zd",argumentNum); //参数的个数 45 46 const char *type = [sig getArgumentTypeAtIndex:3]; 47 NSLog(@"方法签名中下标为3的的参数类型:%s",type); 48 }
4、performSelector 方法演示
1 - (void)performInstanceMethod { 2 //调用一个参数 3 [self performSelector:@selector(oneParameter:) withObject:@"one"]; 4 5 //调用两个参数 6 [self performSelector:@selector(oneParam:twoParam:) withObject:@"1" withObject:@"2"]; 7 } 8 // 一个参数的方法 9 - (void)oneParameter:(NSString *)one { 10 NSLog(@"%@",one); 11 } 12 // 两个参数的方法 13 - (void)oneParam:(NSString *)one twoParam:(NSString *)two { 14 NSLog(@"one:%@-----two:%@", one, two); 15 }
5、invocation使用场景
在与 js 交互中,点击 webview 上某个按钮,获取网页上的一些跳转链接;例如:ml://sendMessage?red=ff&green=aa&blue=33;获取链接之后,再在 oc 中进行处理,获得方法名字符换(sendMessage:red:green:blue),并提取相应的参数值放到数组里面;将方法名字符串和参数一起放到NSInvocation中进行处理,进而调用 oc 中
- (void)sendMessage:(NSString )r green:(NSSring)g blue:(NSString*)b;
6、常见方法及属性
- NSInvocation
// 保留参数,它会将所有参数和self 都retain 一遍 - (void)retainArguments; // 判断参数是否存在,调用retainArguments之前,值为NO,调用之后值为YES
@property(readonly)Bool argumentsRetained;
- NSMethodSignature其他常用方法和属性
// 参数个数 @property(readonly)NSUInteger numberOfArguments; // 获取方法的长度 @property(readonly)NSUInteger frameLength; //是否是单向 - (Bool)isOneWay; // 获取方法返回值的类型 @property(readonly)const char *methodReturnType; // 获取方法返回值的长度 @property(readonly)NSUInteger methodReturnLength; // 获取指定下标的参数类型 - (const char*)getArgumentTypeArIndex:(NSUInteger)idx; // 通过c字符串获得方法签名 + (nullable MethodSignature*)signatureWithObjectCType:(const char*)types;
7、对于NSInvocation的相关扩展
1 #import "NSObject+Exception.h" 2 3 @implementation NSObject (Exception) 4 5 - (id)performSelector:(SEL)aSelector withObjects:(NSArray *)objects { 6 7 //生成方法签名 8 NSMethodSignature *sig = [NSMethodSignature methodSignatureForSelector:aSelector]; 9 if (sig == nil) { //如果方法签名不存在抛出异常 10 [NSException raise:@"exceptionName" format:@"%@not found method",NSStringFromSelector(aSelector)]; 11 } 12 //生成invocation 13 NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig]; 14 invocation.target = self;// 设置调用对象 15 invocation.selector = aSelector;// 设置方法选择器 16 17 NSInteger num = sig.numberOfArguments - 2; // 传递进来的参数个数 18 NSInteger min = MAX(num, objects.count); // 取得参数的数量 19 for (int i = 0; i< min; i++) { 20 id obj = objects[i]; 21 if ([obj isKindOfClass:[NSNull class]]) continue; 22 // 设置参数 23 [invocation setArgument:&obj atIndex:i + 2]; 24 } 25 // 调用方法 26 [invocation invoke]; 27 28 // 获得返回值 29 id value = nil; 30 if (sig.methodReturnLength !=0) { //如果有返回值的话,获取返回值 31 [invocation getReturnValue:&value]; 32 } 33 return value; 34 } 35 @end
世界不会在意你的自尊,人们看的只是你的成就。在你没有成就以前,切勿过分强调自尊。——比尔·盖茨 |