NSInvocation的接口
@interface NSInvocation : NSObject {
@private
__strong void *_frame;
__strong void *_retdata;
id _signature;
id _container;
uint8_t _retainedArgs;
uint8_t _reserved[15];
}
// 通过NSMethodSignature对象创建NSInvocation对象,NSMethodSignature为方法签名类
+ (NSInvocation *)invocationWithMethodSignature:(NSMethodSignature *)sig;
// 获取NSMethodSignature对象
@property (readonly, retain) NSMethodSignature *methodSignature;
// 保留参数,它会将传入的所有参数以及target都retain一遍
- (void)retainArguments;
// 判断参数是否还存在
// 调用retainArguments之前,值为NO,调用之后值为YES
@property (readonly) BOOL argumentsRetained;
// 设置消息调用者,注意:target最好不要是局部变量
@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发送消息,即target执行方法
- (void)invokeWithTarget:(id)target;
@end
NSMethodSignature的接口
@interface NSMethodSignature : NSObject {
@private
void *_private;
void *_reserved[6];
}
// 通过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、根据方法创建签名对象(NSMethodSignature对象)
2、根据签名对象创建调用对象(NSInvocation对象)
3、设置调用对象(NSInvocation对象)的相关信息
4、调用方法
5、获取方法返回值
示例
#import <Foundation/Foundation.h>
@interface SignatureModel : NSObject
@end
#import "SignatureModel.h"
@implementation SignatureModel
- (int)myLog:(int)a param:(int)b parm:(int)c
{
NSLog(@"MyLog:%d,%d,%d", a, b, c);
return a+b+c;
}
- (void)myLog
{
NSLog(@"你好,");
}
SignatureModel *signatureModel = [[SignatureModel alloc] init];
SEL myMethod = @selector(myLog);
SEL myMethod2 = @selector(myLog:param:parm:);
// 创建一个函数签名,这个签名可以是任意的,但需要注意,签名函数的参数数量要和调用的一致。
NSMethodSignature *sig = [[SignatureModel class] instanceMethodSignatureForSelector:myMethod];
NSMethodSignature *sig2 = [[SignatureModel class] instanceMethodSignatureForSelector:myMethod2];
// 通过签名初始化
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
NSInvocation *invocation2 = [NSInvocation invocationWithMethodSignature:sig2];
//注意:target不要设置成局部变量
invocation.target = signatureModel;
invocation2.target = signatureModel;
// 设置selector
[invocation setSelector:myMethod];
[invocation2 setSelector:myMethod2];
int a = 1, b = 2, c = 3;
// 注意:1、这里设置参数的Index 需要从2开始,因为前两个被selector和target占用。
[invocation2 setArgument:&a atIndex:2];
[invocation2 setArgument:&b atIndex:3];
[invocation2 setArgument:&c atIndex:4];
//将c的值设置为返回值
[invocation2 setReturnValue:&c];
int d;
// 取这个返回值
[invocation2 getReturnValue:&d];
NSLog(@"d:%d", d);
//调用方法
[invocation invoke];
//[invocation2 invoke];
[invocation2 invokeWithTarget:signatureModel];
// 获取参数个数
NSInteger count = sig2.numberOfArguments;
// 打印所有参数类型,
// 这里打印的结果是 @ : i i i 它们是Objective-C类型编码
// @ 表示 NSObject* 或 id 类型
// : 表示 SEL 类型
// i 表示 int 类型
for (int i = 0; i < (int)count; i++) {
const char *argTybe = [sig2 getArgumentTypeAtIndex:i];
NSLog(@"参数类型 %s",argTybe);
}
// 获取返回值的类型
const char *returnType = [sig2 methodReturnType];
NSLog(@"返回值的类型 %s",returnType);
2018-03-02 16:07:47.114787+0800 AddMethodDemo[20544:1965850] d:3
2018-03-02 16:07:47.114994+0800 AddMethodDemo[20544:1965850] 你好,
2018-03-02 16:07:47.115120+0800 AddMethodDemo[20544:1965850] MyLog:1,2,3
2018-03-02 16:07:47.115343+0800 AddMethodDemo[20544:1965850] 参数类型 @
2018-03-02 16:07:47.115565+0800 AddMethodDemo[20544:1965850] 参数类型 :
2018-03-02 16:07:47.115765+0800 AddMethodDemo[20544:1965850] 参数类型 i
2018-03-02 16:07:47.116010+0800 AddMethodDemo[20544:1965850] 参数类型 i
2018-03-02 16:07:47.116423+0800 AddMethodDemo[20544:1965850] 参数类型 i
2018-03-02 16:07:47.116660+0800 AddMethodDemo[20544:1965850] 返回值的类型 i