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

三种方式供你选择

  1. 通过KVC来设置
  2. 通过runtime动态改变
  3. 通过 msg_send() 设置

例子:
有这样一个类 PrivateVariablesClass:


@interface PrivateVariablesClass ()
@property (nonatomic, assign) NSInteger priviteNum;
@property (nonatomic, strong) UIView *priviteView;
@end
@implementation PrivateVariablesClass

-(void)showPropertyPrivateVariablesClass
{
    NSLog(@"priviteNum = %@", @(_priviteNum));
    NSLog(@"priviteView = %@", _priviteView);
}

我们在外部改完后,调用 showPropertyPrivateVariablesClass 方法去查看这两个私有属性的值。

1.KVC:

-(void)way1{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    [classA setValue:@(4) forKey:@"_priviteNum"];
    [classA setValue:self.view forKey:@"_priviteView"];
    [classA showPropertyPrivateVariablesClass];
}

控制台打印:

2019-03-04 15:37:05.962204+0800 私有变量传值[45878:581429] priviteNum = 4

2019-03-04 15:37:05.962745+0800 私有变量传值[45878:581429] priviteView = <UIView: 0x7ff224f06590; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x60000378e2a0>>

2.通过runtime动态改变

-(void)way2{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    
    unsigned int outCount = 0;
    Ivar *ivars = class_copyIvarList([PrivateVariablesClass class], &outCount);
    
    for (int i = 0; i < outCount; i ++) {
        Ivar ivar = ivars[i];
        
        const char *ivarName = ivar_getName(ivar);
        
        //这里要注意ARC下, 这个会报错
        /**
         在修改NSInteger型变量的时候,ARC下,编译器不允许你将NSInteger类型的值赋值给id,在buildsetting中将Objective-C Automatic Reference Counting修改为No即可。但是这样工程就会变成MRC,所以,如果是非对象类型就不建议用object_setIvar这样的方法去修改了。
         */

        int a = strcmp(ivarName, "_priviteNum");
        if (strcmp(ivarName, "_priviteNum") == 0) {
            //这种方式传值int类型会报错,不能传入
            object_setIvar(classA, ivar, 22);
        }
        
        if (strcmp(ivarName, "_priviteView") == 0) {
            object_setIvar(classA, ivar, self.view);
        }
    }
    
    [classA showPropertyPrivateVariablesClass];
}

控制台输出结果:

2019-03-04 15:38:25.938643+0800 私有变量传值[45895:582713] priviteNum = 22

2019-03-04 15:38:25.939206+0800 私有变量传值[45895:582713] priviteView = <UIView: 0x7f85675057d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x6000018c0140>>

扫描二维码关注公众号,回复: 5587339 查看本文章

3.msg_send() 去修改 (适用私有属性,不适用私有变量)
既然是私有属性了,必然有setter方法, 那我们动态调用一下。

-(void)way3{
    PrivateVariablesClass *classA = [[PrivateVariablesClass alloc] init];
    ((void (*)(id, SEL, int))(void *) objc_msgSend)((id)classA, @selector(setPriviteNum:) , 33);
    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)classA, @selector(setPriviteView:) , self.view);
    [classA showPropertyPrivateVariablesClass];
}

控制台输出结果:

2019-03-04 15:40:13.489726+0800 私有变量传值[45911:583616] priviteNum = 33

2019-03-04 15:40:13.490237+0800 私有变量传值[45911:583616] priviteView = <UIView: 0x7fd43ad21520; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x600003c78360>>

这里附上git代码

猜你喜欢

转载自blog.csdn.net/ZhaiAlan/article/details/88119557
今日推荐