iOS中如何访问并修改一个类的私有属性

要访问一个类的私有属性,很容易想到使用KVC,其实还有种方法就是利用runtime。但runtime有个短板在于,在ARC下,不支持对基本数据类型的变量进行修改。

示例:

新建Person类,声明name和age两个私有实例变量或property属性并初始化,重写description方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@interface Person()
{
NSString *_name;
}
@property (nonatomic, assign) NSInteger age;
@end

@implementation Person
-(instancetype)init
{
self = [super init];
if (self) {
_name = @"郑郑";
_age = 17;
}
return self;
}

-(NSString *)description
{
return [NSString stringWithFormat:@"niceGirl name=%@,age = %ld",_name,_age];
}

@end

使用KVC对Person的私有变量进行修改:

1
2
3
4
5
6
7
8
9
_niceGirl = [[Person alloc] init];
/*KVC方法访问修改*/
[_niceGirl setValue:@"冰冰棒" forKey:@"name"];
[_niceGirl setValue:@18 forKey:@"age"];
NSLog(@"KVC修改后——%@",_niceGirl);

/*打印结果*/
/*修改前**——niceGirl name=郑郑,age = 17 */
/*KVC修改后——niceGirl name=冰冰棒,age = 18 */

KVC支持对私有实例变量、属性进行修改,包括基本数据类型和Objective-C类型。

使用runtime对私有变量进行修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*利用runtime访问修改*/
unsigned int count = 0;
/*获取ivarlist*/
Ivar *members = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i++) {
Ivar ivar = members[i];
// 将IVar变量转化为字符串,这里获得了属性名
const char *memberName = ivar_getName(ivar);
if (memberName) {
NSString *ivarName = [NSString stringWithUTF8String:memberName];
if ([ivarName containsString:@"name"]) {
object_setIvar(_niceGirl, ivar, @"小糊涂");
}
/*
else if ([ivarName containsString:@"age"]){
object_setIvar(_niceGirl, ivar, @20);
// object_setInstanceVariable(_niceGirl, memberName,(__bridge void *)(@24));
}
*/
}
}
NSLog(@"runtime修改后——%@",_niceGirl);

/*打印结果(runtime没有修改年龄)*/
/*修改前——niceGirl name=郑郑,age = 17*/

注意:object_setIvar(id obj, Ivar ivar, id value)方法不能实现对基本数据类型的修改,在ARC下Ivar object_setInstanceVariable(id obj, const char *name, void *value)不可用,所以也不能实现对私有变量的修改。