iOS runtime(二)runtime之Ivar 详尽

runtime官方文章学习大纲

1.获取成员变量列表

1.1相关函数

Ivar可以看出也是一个变量类型
typedef struct objc_ivar *Ivar;
//获取成员变量列表
Ivar *class_copyIvarList(Class cls, unsigned int * outCount) 
//获取成员变量类型编码
const char *ivar_getTypeEncoding(Ivar  v) 
//获取成员变量名称
const char *ivar_getName(Ivar  v) 

1.2实例代码

#import "ViewController.h"
#import 

@interface ViewController ()

@property (nonatomic,strong)NSString *name;
@property (nonatomic,assign)NSString *age;
@property (nonatomic,strong)NSString *address;

@end

@implementation ViewController

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

- (void)class_copyIvarList{
    uint count;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (unsigned int i = 0; i < count; i ++) {
        Ivar ivar = ivars[i];
        //获取成员变量名称
        NSString* name = @(ivar_getName(ivar));
        //获取成员变量数据类型
        NSString * type = @(ivar_getTypeEncoding(ivar));
        NSLog(@"类型为 %@ 的 %@ ",type, name);
    }
    free(ivars);
}

1.3打印数据

2018-05-26 10:02:36.597199+0700 runTimer[6417:1017717] 类型为 @"NSString" 的 _name 
2018-05-26 10:02:36.597586+0700 runTimer[6417:1017717] 类型为 @"NSString" 的 _age 
2018-05-26 10:02:36.597852+0700 runTimer[6417:1017717] 类型为 @"NSString" 的 _address 

1.4查漏补缺

 //通过变量名称获取类中的实例成员变量
 Ivar class_getInstanceVariable(Class cls, const char * name)

实例代码及打印数据:

#import "ViewController.h"
#import 

@interface ViewController ()

@property (nonatomic,strong)NSString *name;
@property (nonatomic,assign)NSString *age;
@property (nonatomic,strong)NSString *address;

@end

@implementation ViewController

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

- (void)class_getInstanceVariable{
    //注意成员变量必须“_名称”
    Ivar name_Ivar = class_getInstanceVariable([self class], "_name");
    NSString * name_type = @(ivar_getTypeEncoding(name_Ivar));
    NSString *name_str = @(ivar_getName(name_Ivar));
    NSLog(@"name_type:%@",name_type);
    NSLog(@"name_str:%@",name_str);
}
打印数据:
2018-05-26 10:41:17.384676+0700 runTimer[7091:1043835] name_type:@"NSString"
2018-05-26 10:41:17.384831+0700 runTimer[7091:1043835] name_str:_name

2.添加成员变量

2.1相关函数

//为元类添加成员变量
BOOL class_addIvar(Class cls, const char * name, size_t size, 
              uint8_t alignment, const char * types) 
//添加类 superclass 类是父类   name 类的名字  size_t 类占的空间
Class objc_allocateClassPair(Class superclass, const char * name,size_t extraBytes) 
//注册类
void objc_registerClassPair(Class  cls) 
//销毁类
void objc_disposeClassPair(Class _Nonnull cls) 

2.2实例代码

  1. People.h
#import 

@interface People : NSObject

@end
  1. People.m
#import "People.h"

@implementation People

@end

3.实例调用:

#import "ViewController.h"
#import 
#import "People.h"
@interface ViewController ()
@end

@implementation ViewController

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

- (void)class_addIvar{
    Class P_Class = objc_allocateClassPair([NSObject class], "_People", 0);
    BOOL isOk = NO;
    isOk = class_addIvar(P_Class,"myVar", sizeof(id), log2(sizeof(id)), "@");
    isOk == YES ? nil : NSLog(@"failed on class_addIvar");
    objc_registerClassPair(P_Class);
    id myobj = [[P_Class alloc] init];
    [myobj setValue:@"test" forKey:@"myVar"];
    NSLog(@"myVar: %@", [myobj valueForKey:@"myVar"]);
    myobj = nil;//当_People类或者它的子类的实例还存在,则不能调用objc_disposeClassPair这个方法;因此这里要先销毁实例对象后才能销毁类;
    objc_disposeClassPair(P_Class);
    
}
打印数据:
2018-05-27 10:19:51.251273+0700 runTimer[14245:1323729] myVar: test

总结:
关于这个方法,说真的让我产生了一些疑惑,至今也没有得到答案,也希望看到这篇文章对runtime有一定理解朋友可以给予一定的解释,

  • 疑问一:objc_allocateClassPair 在刚开始我创建获取元类时我得到总是nil,在网上查了很多资料但是我没有得到答案,后来是因为自己是性的在累名前加“_” 竟然成功的获取了,我没有明白原因。
  • 疑问二:关于元类说实话我之前也是简单的知道,个人理解是关于类描述的一个类,但是我始终不能明白在元类中添加成员变量,这样做会苹果官方有什么样的深意。

3 object_setIvar object_getIvar

3.1相关函数

//相当于set方法
void object_setIvar(id obj, Ivar ivar, id value) 
//相当于get方法
id object_getIvar(id obj, Ivar ivar) 

3.2实例代码

1.People.h

#import 

@interface People : NSObject
@property (nonatomic,strong)NSString *phone;
@end

  1. People.m
#import "People.h"

@implementation People

@end

3.实例代码调用:

#import "ViewController.h"
#import 
#import 
#import "People.h"
@interface ViewController ()
@property (nonatomic,strong)People *p;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    Ivar ivar = class_getInstanceVariable([People class], "_phone");
    People *p = [[People alloc] init];
    p.phone = @"1322432423";
    id name1 = object_getIvar(p, ivar);
    NSLog(@"name1:%@",name1);
    object_setIvar(p, ivar, @"1322432423");
    id name2 = object_getIvar(p, ivar);
    NSLog(@"name2:%@",name2);
}
打印数据:
2018-05-27 11:05:04.551576+0700 runTimer[14991:1353337] name1:1322432423
2018-05-27 11:05:04.551717+0700 runTimer[14991:1353337] name2:1322432423

总结:
看到这里的时候我想大家已经很明白了 这两个方法 基本上等同于set get方法。

4.未做解析方法:

ivar_getOffset
class_setWeakIvarLayout
object_setIvarWithStrongDefault
class_getWeakIvarLayout
class_getIvarLayout

好了 就那么多了 还有一些方法没有讲,太懒了,就不一一解析了。
下一章,关于runtime 关于method的解析

你可能感兴趣的:(iOS runtime(二)runtime之Ivar 详尽)