在 iOS中可以直接调用某个对象的消息方式有两种:
一种是performSelector:withObject;
再一种就是NSInvocation。
第一种方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那就需要做些额外工作才能搞定。那么在这种情况下,我们就可以使用NSInvocation来进行这些相对复杂的操作。在高级点的, block的结构体里面也是有函数的, 函数就可以通过NSInvocation调用 , 比较出名的Aspects框架就使用了NSInvocation调用block.
1、NSInvocation的作用
封装了 方法调用对象、方法选择器、参数、返回值等,可以给对象发送一个参数大于两个的消息;
2、优势
NSInvocation,它可以设置多个参数;
3、使用方式
- 通过NSObject(或者子类都可以) 生成方法签名
- 通过方法签名生成 NSInvocation
- 设置方法调用者
- 设置方法选择器
- 设置参数
- 如果有返回值,获取返回值
4.invocation代码演示
-(void)invocationInstance{
// 1.通过方法调用者创建方法签名;此方法是NSObject(或者子类)的方法
NSMethodSignature *sig = [[self class] instanceMethodSignatureForSelector:@selector(take:andAge:andBlue:)];
// 2.通过方法签名 生成NSInvocation
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
// 3.对invocation设置 方法调用者
invocation.target = self;
// 4.对invocation设置 方法选择器
invocation.selector = @selector(take:andAge:andBlue:);
// 5.对invocation设置 参数
NSString *name = @"张三";
NSString *age = @"20";
NSString *color = @"red";
//注意:设置的参数必须从2开始;因为0和1 已经被self ,_cmd 给占用了
[invocation setArgument:&name atIndex:2];
[invocation setArgument:&age atIndex:3];
[invocation setArgument:&color atIndex:4];
// 6.执行invocation
[invocation invoke];
// 7.判断 方法签名 判断是否有返回值
// 方法签名的返回值类型,下面随便举了2个例子
const char *sigretun = sig.methodReturnType;
//方法签名返回值长度; 如果是字符串返回8,数字返回4,没有返回值返回0;
NSUInteger siglength = sig.methodReturnLength;
if (siglength !=0) { //有返回值
if (strcmp(sigretun, "@") == 0) {
NSString *returnStr;
[invocation getReturnValue:&returnStr];
NSLog(@"字符串返回值:%@",returnStr);
}else if (strcmp(sigretun, "q")==0){
NSInteger a = 0;
[invocation getReturnValue:&a];
NSLog(@"原始返回值:%zd",a);
a=100;
[invocation setReturnValue:&a];
NSLog(@"新设定的返回值:%zd",a);
}
}else{ //没有返回值
NSLog(@"没有返回值");
}
// 8.常用方法
NSUInteger argumentNum = sig.numberOfArguments;
NSLog(@"%zd",argumentNum); //参数的个数
for(int i=0;i<argumentNum;i++){
const char *type = [sig getArgumentTypeAtIndex:i];
NSLog(@"下标:%d 参数类型:%s",i,type);
}
}
//三个参数的方法
-(void)take:(NSString *)name andAge:(NSString *)age andBlue:(NSString *)color{
NSLog(@"%@-%@-%@",name,age,color);
// return 7;
}
5.常见方法及属性
- 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;
在附上一个实例,解决了ipad 横屏时,进入app 右侧黑屏的问题
//解决横屏启动时,app右侧是黑的问题
if ([[UIApplication sharedApplication] respondsToSelector:@selector(setStatusBarOrientation:)]){
SEL selector = NSSelectorFromString(@"setStatusBarOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIApplication instanceMethodSignatureForSelector:selector]];
UIDeviceOrientation orentation = UIDeviceOrientationPortrait;
[invocation setSelector:selector];
[invocation setTarget:[UIApplication sharedApplication]];
[invocation setArgument:&orentation atIndex:2];
[invocation invoke];
}