一、介绍
在 iOS中可以直接调用方法的方式有两种:
1、performSelector:withObject;
2、NSInvocation
前者最多只能有两个参数,多参的情况下需要用NSInvocation来处理。
NSInvocation.h文件:
@interface NSInvocation : NSObject {
@private
void *_frame;
void *_retdata;
id _signature;
id _container;
uint8_t _retainedArgs;
uint8_t _reserved[15];
}
// 通过NSMethodSignature对象创建NSInvocation对象(NSMethodSignature为方法签名类)
+ (NSInvocation *)invocationWithMethodSignature:(NSMethodSignature *)sig;
@property (readonly, retain) NSMethodSignature *methodSignature;
// 保留参数,将传入的所有参数以及target都retain一遍
- (void)retainArguments;
// 调用retainArguments之前,值为NO,调用之后值为YES
@property (readonly) BOOL argumentsRetained;
// 消息调用者
@property (nullable, assign) id target;
// 调用的消息
@property SEL selector;
// 获取消息返回值
- (void)getReturnValue:(void *)retLoc;
// 设置消息返回值
- (void)setReturnValue:(void *)retLoc;
// 获取消息参数
- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
// 设置消息参数
- (void)setArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
// 发送消息(执行)
- (void)invoke;
// target发送消息
- (void)invokeWithTarget:(id)target;
@end
上面介绍到创建一个NSInvocation对象需要NSMethodSignature对象(方法签名类),所以我们再了解下NSMethodSignature类
@interface NSMethodSignature : NSObject {
@private
void *_private;
void *_reserved[5];
unsigned long _flags;
}
// 通过Objective-C类型编码(Objective-C Type Encodings)创建一个NSMethodSignature对象
+ (nullable NSMethodSignature *)signatureWithObjCTypes:(const char *)types;
// 参数个数
@property (readonly) NSUInteger numberOfArguments;
// 获取参数类型
- (const char *)getArgumentTypeAtIndex:(NSUInteger)idx NS_RETURNS_INNER_POINTER;
// 所有参数占用的字节数
@property (readonly) NSUInteger frameLength;
// 通过分布式对象调用时,接收者是否是异步的。
- (BOOL)isOneway;
// 方法返回类型
@property (readonly) const char *methodReturnType NS_RETURNS_INNER_POINTER;
// 返回值所需的字节数。
@property (readonly) NSUInteger methodReturnLength;
@end
二、使用
1、无参无返
- (void)invocation{
SEL sel = @selector(run);
NSMethodSignature *sign = [[self class] instanceMethodSignatureForSelector:sel];
NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sign];
invo.target = self;
invo.selector = sel;
[invo invoke];
}
- (void)run{
NSLog(@"run");
}
2、有参无返
- (void)invocation{
SEL sel = @selector(runArg1:arg2:arg3:);
NSMethodSignature *sign = [[self class] instanceMethodSignatureForSelector:sel];
NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sign];
invo.target = self;
invo.selector = sel;
// 参数设置
NSString *name = @"小明";
NSInteger age = 18;
NSArray *family = @[@"爷爷",@"奶奶",@"爸爸",@"妈妈"];
// 0是target 1是selector
[invo setArgument:&name atIndex:2];
[invo setArgument:&age atIndex:3];
[invo setArgument:&family atIndex:4];
[invo invoke];
}
- (void)runArg1:(NSString *)arg1 arg2:(NSInteger)arg2 arg3:(NSArray *)arg3{
NSLog(@"%@ %ld %@",arg1,(long)arg2,arg3);
}
3、有参有返
- (void)invocation{
SEL sel = @selector(runArg1:arg2:arg3:);
NSMethodSignature *sign = [[self class] instanceMethodSignatureForSelector:sel];
NSInvocation *invo = [NSInvocation invocationWithMethodSignature:sign];
invo.target = self;
invo.selector = sel;
// 参数设置
NSString *name = @"小明";
NSInteger age = 18;
NSArray *family = @[@"爸爸",@"妈妈"];
// 0是target 1是selector
[invo setArgument:&name atIndex:2];
[invo setArgument:&age atIndex:3];
[invo setArgument:&family atIndex:4];
[invo invoke];
// 获取返回值
void *re;
[invo getReturnValue:&re];
NSLog(@"%@",re);
}
- (NSString *)runArg1:(NSString *)arg1 arg2:(NSInteger)arg2 arg3:(NSArray *)arg3{
NSLog(@"%@ %ld %@",arg1,(long)arg2,arg3);
return [NSString stringWithFormat:@"%@今年%ld岁,家庭成员有%@,%@",arg1,(long)arg2,arg3[0],arg3[1]];
}
注:这里要说明一点,若用NSString 类型去获取返回值会crash。具体看这篇
参考:https://blog.csdn.net/ssirreplaceable/article/details/53375972