您的位置:首页 > 其它

NSInvocation简单用法

2016-02-16 14:50 477 查看
在 iOS中可以直接调用某个对象的消息方式有两种:

一种是performSelector:withObject     另一种就是NSInvocation

第一种方式比较简单,能完成简单的调用。但是对于>2个的参数或者有返回值的处理,那就需要做些额外工作才能搞定。那么在这种情况下,我们就可以使用NSInvocation来进行这些相对复杂的操作。

1、

DZPerson.h:

#import <Foundation/Foundation.h>

@interface DZPerson : NSObject

@end


.h文件中并不需要有方法的声明

DZPerson.m

#import "DZPerson.h"

@implementation DZPerson

- (void) showName:(NSString *) name {
NSLog(@"name : %@", name);
}
- (void) showName:(NSString *) name andAge:(NSUInteger) age {
NSLog(@"name : %@, age : %lu", name, (unsigned long)age);
}
- (NSString *) getAgeAndNameWithName:(NSString *) name {
NSString * str = [NSString stringWithFormat:@"age : 15, name : %@", name];
NSLog(@"%@", str);
return str;
}

- (NSInteger) getAge {
return 1970;
}

@end


2、测试:

代码中有详细的注释:

//
//  ViewController.m
//  001-nsinvocation
//
//

#import "ViewController.h"
#import "DZPerson.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];

DZPerson * p1 = [[DZPerson alloc] init];

//1、一个参数
NSMethodSignature * methodSignature1 = [[p1 class] instanceMethodSignatureForSelector:@selector(showName:)];
NSInvocation * invocation1 = [NSInvocation invocationWithMethodSignature:methodSignature1];

[invocation1 setTarget:p1];
[invocation1 setSelector:@selector(showName:)];

NSString * name = @"ldz";

//如果此消息有参数需要传入,那么就需要按照如下方法进行参数设置,需要注意的是,atIndex的下标必须从2开始。原因为:0 1 两个参数已经被target 和selector占用
[invocation1 setArgument:&name atIndex:2];
//防止参数被释放掉
[invocation1 retainArguments];
//调用
[invocation1 invoke];

//2、两个参数
NSMethodSignature * methodSignature2 = [[p1 class] instanceMethodSignatureForSelector:@selector(showName:andAge:)];
NSInvocation * invocation2 = [NSInvocation invocationWithMethodSignature:methodSignature2];

[invocation2 setTarget:p1];
[invocation2 setSelector:@selector(showName:andAge:)];

NSUInteger age = 18;

[invocation2 setArgument:&name atIndex:2];
[invocation2 setArgument:&age atIndex:3];
[invocation2 retainArguments];
[invocation2 invoke];

//3、有返回值的情况
NSMethodSignature * methodSignature3 = [[p1 class] instanceMethodSignatureForSelector:@selector(getAgeAndNameWithName:)];
NSInvocation * invocation3 = [NSInvocation invocationWithMethodSignature:methodSignature3];

[invocation3 setTarget:p1];
[invocation3 setSelector:@selector(getAgeAndNameWithName:)];

[invocation3 setArgument:&name atIndex:2];
[invocation3 retainArguments];
[invocation3 invoke];

//获取返回值类型
const char * returnValueType = methodSignature3.methodReturnType;
NSLog(@"returnValueType : %s", returnValueType);

//声明一个返回值变量
id returnValue;

//如果没有返回值,也就是消息声明为void,那么returnValue = nil
if (!strcmp(returnValueType, @encode(void))) {
NSLog(@"没有返回值,即返回值类型为void");
returnValue = nil;
}else if (!strcmp(returnValueType, @encode(id))){
//如果返回值为对象,那么为变量赋值
NSLog(@"返回值类型为对象");
[invocation3 getReturnValue:&returnValue];
}else {
//如果返回值为普通类型,如NSInteger, NSUInteger ,BOOL等
NSLog(@"返回类型为普通类型");

//首先获取返回值长度
NSUInteger returnValueLenth = methodSignature3.methodReturnLength;

//根据长度申请内存
void * retValue = (void *)malloc(returnValueLenth);

//为retValue赋值
[invocation3 getReturnValue:retValue];

if (!strcmp(returnValueType, @encode(BOOL))) {
returnValue = [NSNumber numberWithBool:*((BOOL *)retValue)];
}else if (!strcmp(returnValueType, @encode(NSInteger))){
returnValue = [NSNumber numberWithInteger:*((NSInteger *) retValue)];
}
//。。。  余下省略

}

NSLog(@"返回值是:%@", returnValue);

//4、返回类型为普通类型的情况

NSMethodSignature * methodSignature4 = [[p1 class] instanceMethodSignatureForSelector:@selector(getAge)];
NSInvocation * invocation4 = [NSInvocation invocationWithMethodSignature:methodSignature3];

[invocation4 setTarget:p1];
[invocation4 setSelector:@selector(getAge)];

[invocation4 invoke];

//获取返回值类型
const char * returnValueType4 = methodSignature4.methodReturnType;
NSLog(@"returnValueType : %c", *returnValueType4);

//声明一个返回值变量
id returnValue4;

//如果没有返回值,也就是消息声明为void,那么returnValue = nil
if (!strcmp(returnValueType4, @encode(void))) {
NSLog(@"没有返回值,即返回值类型为void");
returnValue4 = nil;
}else if (!strcmp(returnValueType4, @encode(id))){
//如果返回值为对象,那么为变量赋值
NSLog(@"返回值类型为对象");
[invocation4 getReturnValue:&returnValue4];
}else {
//如果返回值为普通类型,如NSInteger, NSUInteger ,BOOL等
NSLog(@"返回类型为普通类型");

//首先获取返回值长度
NSUInteger returnValueLenth4 = methodSignature4.methodReturnLength;

//根据长度申请内存
void * retValue4 = (void *)malloc(returnValueLenth4);

//为retValue赋值
[invocation4 getReturnValue:retValue4];

if (!strcmp(returnValueType4, @encode(BOOL))) {
returnValue4 = [NSNumber numberWithBool:*((BOOL *)retValue4)];
}else if (!strcmp(returnValueType4, @encode(NSInteger))){
returnValue4 = [NSNumber numberWithInteger:*((NSInteger *) retValue4)];
}
//。。。  余下省略

}

NSLog(@"返回值是:%@", returnValue4);

}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end


输出:

2016-02-16 14:23:00.093 001-nsinvocation[2766:96619] name : ldz
2016-02-16 14:23:00.094 001-nsinvocation[2766:96619] name : ldz, age : 18
2016-02-16 14:23:00.094 001-nsinvocation[2766:96619] age : 15, name : ldz
2016-02-16 14:23:00.094 001-nsinvocation[2766:96619] returnValueType : @
2016-02-16 14:23:00.094 001-nsinvocation[2766:96619] 返回值类型为对象
2016-02-16 14:23:00.094 001-nsinvocation[2766:96619] 返回值是:age : 15, name : ldz
2016-02-16 14:23:00.094 001-nsinvocation[2766:96619] returnValueType : q
2016-02-16 14:23:00.095 001-nsinvocation[2766:96619] 返回类型为普通类型
2016-02-16 14:23:00.095 001-nsinvocation[2766:96619] 返回值是:1970


3、其中Objective-C类型编码为:

编码含义
cchar
iint
sshort
llong

在64位程序中,l为32位
qlong long
C(大写)unsigned char
I(大写)unsigned int
S(大写)unsigned short
Lunsigned long
Qunsigned long long
ffloat
ddouble
BC++标准的bool或者C99标准的_Bool
vvoid
*字符串(char *)
@对象(无论是静态指定的还是通过id引用的)
#类(class)
:方法选标(SEL)
[array type]数组
{name=type...}结构体
(name=type...)联合体
bnumnum个bit的位域
^typetype类型的指针
?未知类型(其他的情况,一般用来指函数指针)
[align=center]
[/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息