美文网首页
Runtime修改属性(包括私有)-2021-02-23-周二

Runtime修改属性(包括私有)-2021-02-23-周二

作者: 勇往直前888 | 来源:发表于2021-02-23 19:24 被阅读0次

私有属性

在类扩展中的私有属性,只有类自己改,其他类在外部是不能修改的。

@interface Person ()

// 昵称;私有属性
@property (nonatomic, copy) NSString *nickname;

@end
- (void)viewDidLoad {
    [super viewDidLoad];
    // 初始化
    self.person = [[Person alloc] init];
    
    // 公共属性,可以在外部设置
    self.person.age = 30;
    self.person.name = @"小明";
    // nickName是私有属性,无法设置
    NSLog(@"%@", self.person);
}

输出内容如下:nickName的值为默认甚至的@"nil"

2021-02-23 19:07:41.783388+0800 RuntimeDemo[7583:522583] <Person: 0x60000262a660> {
  nickname = nil;
  name = 小明;
  age = 30;
}

如何修改私有属性

属性其实是成员变量+set/get;所以直接修改成员就可以改变属性的值。
runtime中的函数class_copyIvarList可以得到对象的成员变量。

// 修改属性值
- (IBAction)modifyButtonTouched:(id)sender {
    NSLog(@"修改前:");
    NSLog(@"%@", self.person);
    unsigned int count = 0;
    Ivar *ivar = class_copyIvarList(self.person.class, &count);
    for (int i = 0; i < count; i++) {
        Ivar tempIvar = ivar[I];
        const char *varName = ivar_getName(tempIvar);
        NSString *varNameString = [NSString stringWithUTF8String:varName];
             
        // 名字;公共属性,可以修改
        if ([varNameString isEqualToString:@"_name"]) {
            object_setIvar(self.person, tempIvar, @"小明的新名字");
        }
        
        // 年龄;值类型;感觉上修改成功了;但是NSNumber的打印(就是Description)不正常;
//        if ([varNameString isEqualToString:@"_age"]) {
//            object_setIvar(self.person, tempIvar, @11);
//        }
        
        // 昵称是私有属性,也能修改
        if ([varNameString isEqualToString:@"_nickname"]) {
            object_setIvar(self.person, tempIvar, @"小明的昵称");
        }
    }
    
    // 释放
    free(ivar);
    
    NSLog(@"修改后:");
    NSLog(@"%@", self.person);
}

测试一下

2021-02-23 19:11:21.785616+0800 RuntimeDemo[7583:522583] 修改前:
2021-02-23 19:11:21.786100+0800 RuntimeDemo[7583:522583] <Person: 0x60000262a660> {
  nickname = nil;
  name = 小明;
  age = 30;
}
2021-02-23 19:11:21.786434+0800 RuntimeDemo[7583:522583] 修改后:
2021-02-23 19:11:21.786871+0800 RuntimeDemo[7583:522583] <Person: 0x60000262a660> {
  nickname = 小明的昵称;
  name = 小明的新名字;
  age = 30;
}

从打印信息可以看出,不管是公有属性name,还是私有属性nickname,在runtime这一层都是一样的,没有任何区别。

问题

对于值类型,比如这里的age,应该能够修改成功,但是打印出来的内容不正常

2021-02-23 19:14:52.547713+0800 RuntimeDemo[7609:526593] 修改前:
2021-02-23 19:14:52.547986+0800 RuntimeDemo[7609:526593] <Person: 0x60000185c920> {
  nickname = nil;
  name = 小明;
  age = 30;  
}
2021-02-23 19:14:52.548178+0800 RuntimeDemo[7609:526593] 修改后:
2021-02-23 19:14:52.548427+0800 RuntimeDemo[7609:526593] <Person: 0x60000185c920> {
  nickname = 小明的昵称;
  name = 小明的新名字;
  age = -4059584697397031632; 
}

代码中,明明设置的是object_setIvar(self.person, tempIvar, @11);
打印出来的却是age = -4059584697397031632;

推测

应该修改成功了,只不过值类型在设置的时候需要包装成NSNumber类型,所以修改是对的,但是打印的内容由问题。
可以断点看一下:

image.png

但是显示是不正常的:

image.png

Demo地址

RuntimeDemo

相关文章

网友评论

      本文标题:Runtime修改属性(包括私有)-2021-02-23-周二

      本文链接:https://www.haomeiwen.com/subject/tcrdfltx.html