Runtime访问私有变量和方法及KVO访问

一、Class

在之前的文章中我们提到,所有的对象都有个isa指针指向它对应的类Class,而Class是一个objc_class结构体,结构体中:

  • 实例变量列表objc_ivar_list
  • 方法列表objc_method_list
    对应的runtime获取方法:
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
Method *class_copyMethodList(Class cls, unsigned int *outCount)  

首先我们先创建一个Test类:

//
//  Test.h
//  RuntimeKVC
//
//  Created by z on 2019/5/24.
//  Copyright © 2019年 com.jzsec. All rights reserved.
//

#import 

NS_ASSUME_NONNULL_BEGIN

@interface Test : NSObject
{
    @public
    NSString *name;
    
    /* 头文件中定义私有变量,默认为@protected */
    @private
    NSString *major;
}

@property (nonatomic, strong) Test *childTest;

@end

NS_ASSUME_NONNULL_END
//
//  Test.m
//  RuntimeKVC
//
//  Created by z on 2019/5/24.
//  Copyright © 2019年 com.jzsec. All rights reserved.
//

#import "Test.h"

@interface Test ()
{
    /* 类扩展区域定义私有变量,默认j就是@private */
    int age;
}

/* 类扩展区域定义私有属性 */
@property (nonatomic, copy) NSString *job;

/* 类扩展区域定义私有变量,默认j就是@private */
- (void)test;

@end

@implementation Test

-(void)test
{
    NSLog(@"这是个私有实例方法");
}

@end
二、Runtime访问

runtime暴力访问私有属性、私有变量和私有方法

//获取实例变量列表
        unsigned int count = 0;
        Ivar *members = class_copyIvarList([Test class], &count);
        //打印所有的变量名及其类型 访问私有属性和变量
        for (int i=0; i
/* 暴力访问私有方法 */
        //获取类对象方法列表
        unsigned int countM = 0;
        Method *methods = class_copyMethodList([Test class], &countM);
        for (int i=0; i

打印结果:

2019-08-08 18:01:44.593507+0800 RuntimeKVC[23807:412395] name:name type:@"NSString"
2019-08-08 18:01:44.593616+0800 RuntimeKVC[23807:412395] name=老王
2019-08-08 18:01:44.593635+0800 RuntimeKVC[23807:412395] name:major type:@"NSString"
2019-08-08 18:01:44.593676+0800 RuntimeKVC[23807:412395] major=计算机
2019-08-08 18:01:44.593691+0800 RuntimeKVC[23807:412395] name:age type:i
2019-08-08 18:01:44.593745+0800 RuntimeKVC[23807:412395] age=30
2019-08-08 18:01:44.593761+0800 RuntimeKVC[23807:412395] name:_childTest type:@"Test"
2019-08-08 18:01:44.593784+0800 RuntimeKVC[23807:412395] name:_job type:@"NSString"
2019-08-08 18:01:44.593803+0800 RuntimeKVC[23807:412395] job=工程师
2019-08-08 18:01:44.593884+0800 RuntimeKVC[23807:412395] method:newProperty
2019-08-08 18:01:44.593961+0800 RuntimeKVC[23807:412395] method:setNewProperty:
2019-08-08 18:01:44.593990+0800 RuntimeKVC[23807:412395] method:setChildTest:
2019-08-08 18:01:44.594044+0800 RuntimeKVC[23807:412395] method:childTest
2019-08-08 18:01:44.594087+0800 RuntimeKVC[23807:412395] method:test
2019-08-08 18:01:44.605142+0800 RuntimeKVC[23807:412395] 这是个私有实例方法
2019-08-08 18:01:44.605186+0800 RuntimeKVC[23807:412395] method:.cxx_destruct
2019-08-08 18:01:44.605276+0800 RuntimeKVC[23807:412395] method:job
2019-08-08 18:01:44.605300+0800 RuntimeKVC[23807:412395] method:setJob:
三、KVO访问

在系统的类目中NSObject(NSKeyValueCoding),通过这两个方法,就可以用key来读取和设置属性的值:

- (void)setValue:(nullable id)value forKey:(NSString *)key;
- (nullable id)valueForKey:(NSString *)key;
//nullable作用:表示可以为空;nonnull作用:不能为空

在通过key查找对应的属性或变量时:

  1. 先查找对象的类中是否存在与key对应的访问器方法;
  2. 查找与key名称相同并且带“_”前缀的成员变量;
  3. 与key名称相同的属性;
  4. 以上都没有,则调用setValue:forUndefinedKey:方法。
/* KVO暴力访问私有属性和私有变量 */
        [test setValue:@"testName" forKey:@"name"];
        NSString *tname = [test valueForKey:@"name"];
        [test setValue:@"18" forKey:@"age"];
        NSString *tage = [test valueForKey:@"age"];
        [test setValue:@"mathmetics" forKey:@"major"];
        NSString *tmajor = [test valueForKey:@"major"];
        NSLog(@"name:%@ age:%@ major:%@", tname, tage, tmajor);

        Test *child = [Test new];
        test.childTest = child;
        child->name = @"晨光";
        NSString *cname = [test valueForKeyPath:@"childTest.name"];
        NSLog(@"test.childTest.name:%@", cname);
        [test setValue:@"傻×" forKeyPath:@"childTest.name"];
        NSString *cname1 = [test valueForKeyPath:@"childTest.name"];
        NSLog(@"test.childTest.name:%@", cname1);

打印结果:

2019-08-08 18:01:44.605938+0800 RuntimeKVC[23807:412395] name:testName age:18 major:mathmetics
2019-08-08 18:01:44.606054+0800 RuntimeKVC[23807:412395] test.childTest.name:晨光
2019-08-08 18:01:44.606084+0800 RuntimeKVC[23807:412395] test.childTest.name:傻×

你可能感兴趣的:(Runtime访问私有变量和方法及KVO访问)