Objective-C RunTimecodes

runtime中的ivar和objc_property_t

2018-08-10  本文已影响0人  mrChan1234

在以前的文章,我写了一个入门理解什么是runtime,runtime用来干什么,在iOS开发中,一个合格的程序员是要适当地理解一些偏底层的东西,至少我认为是这样的,理解了runtime的一些东西可以帮助iOS程序员更好的写代码,明白自己写的代码在编辑器里面都经历了什么,我们使用clang命令可以看到我们写的代码被编译成了C ++文件,打开我们可以看到一些源码,在前面写了runtime常用的一些操作,一般常用的使用property和ivar来进行解档归档,那么ivar和property有什么区别呢?
我们可以从下面的打印中看到:
我们声明一个person类,加上属性和私有变量,看分别遍历他的property和ivar属性如下:


person.png property & ivar.png
objc_property t属性是一个类的加上@property关键字的属性,即自动实现了setter和getter方法的属性,而ivar是遍历了一个类所有的属性(包括property属性,自动在前面加上了下划线),二者的区别在这里,打开struct指针声明你会看到:
typedef objc_ivar * Ivar:
objc_ivar.png
typedef struct objc_property *objc_property_t:
objc_property_t.png
objc_property_t特性相关编码
属性的特性字符串 以 T@encode(type) 开头, 以 V实例变量名称 结尾,中间以特性编码填充,通过property_getAttributes即可查看

特性编码 具体含义
R readonly
C copy
& retain
N nonatomic
G(name) getter=(name)
S(name) setter=(name)
D @dynamic
W weak
P 用于垃圾回收机制

我们可以使用这两者动态创建一个类并为其添加属性:

ivar创建添加
- (void)dyamaticCreateAClass {
    //创建一个类
    Class People = objc_allocateClassPair([NSObject class], "People", 0);
    //添加成员变量
    BOOL addNameSucess = class_addIvar(People, "_name", sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
    if (addNameSucess) {
        NSLog(@"变量添加成功,_name");
    }
    
    BOOL addAgeSucess = class_addIvar(People, "_age", sizeof(int), log2(sizeof(int)), @encode(int));
    if (addAgeSucess) {
        NSLog(@"变量添加成功,_age");
    }
    //完成People类的创建
    objc_registerClassPair(People);
    
    unsigned int count = 0;
    Ivar *vars = class_copyIvarList(People, &count);
    for (int i = 0 ; i < count; i ++) {
        NSString *varName = [NSString stringWithUTF8String:ivar_getName(vars[i])];
        NSString *varType = [NSString stringWithUTF8String:ivar_getTypeEncoding(vars[i])];
        NSLog(@"varName = %@,varType = %@",varName,varType);
    }
    
    //释放
    free(vars);
    //为变量赋值
    id Chan = [People new];
    Ivar nameVar = class_getInstanceVariable(People, "_name");
    object_setIvar(Chan, nameVar, @"Chan");
    
    Ivar ageVar =  class_getInstanceVariable(People, "_age");
    object_setIvar(Chan, ageVar, @(24));
    NSLog(@"name = %@,age = %@",object_getIvar(Chan, nameVar),object_getIvar(Chan, ageVar));
    /*
     2018-08-08 11:29:08.909155+0800 APIDemo[4719:180037] 变量添加成功,_name
     2018-08-08 11:29:08.909481+0800 APIDemo[4719:180037] 变量添加成功,_age
     2018-08-08 11:29:08.909631+0800 APIDemo[4719:180037] varName = _name,varType = @
     2018-08-08 11:29:08.909734+0800 APIDemo[4719:180037] varName = _age,varType = i
     2018-08-08 11:29:42.682061+0800 APIDemo[4719:180037] name = Chan,age = 24
     */
}
使用objc_property_t添加属性
Class People = objc_allocateClassPair([NSObject class], "People", 0);
  objc_registerClassPair(People);
  //T@
  objc_property_attribute_t attribute1;
  attribute1.name = "T";
  attribute1.value=@encode(NSString*);
  //Noatomic
  objc_property_attribute_t attribute2 = {"N",""};//value无意义时通常设置为空
  //Copy
  objc_property_attribute_t attribute3 = {"C",""};
  //V_属性名
  objc_property_attribute_t attribute4 = {"V","_name"};
  //特性数组
  objc_property_attribute_t attributes[] ={attribute1,attribute2,attribute3,attribute4};
  //向People类中添加名为name的属性,属性的4个特性包含在attributes中
  class_addProperty(People, "name", attributes, 4);
  //获取类中的属性列表
  unsigned int propertyCount;
  objc_property_t * properties = class_copyPropertyList(People, &propertyCount);
  for (int i = 0; i<propertyCount; i++) {
      NSLog(@"属性的名称为 : %s",property_getName(properties[i]));
      NSLog(@"属性的特性字符串为: %s",property_getAttributes(properties[i]));
  }
  //释放属性列表数组
  free(properties);

读到这里你会发现,你以前常用的一些常用控件,你设置他的属性或者说你遍历他的一些属性,你会发现你可以根据KVC或者KVO来设置或监测一些Apple给你的官方API 里面没有给你的一些属性,实现一些以前不能实现的功能,就比如UIPageControl这个控件,其实遍历他的ivar属性你会发现,你可以通过KVC来设置小圆点的图片,增加了扩展性。当然这只是其中一个例子,但是这只是思想,可以方便你更好的理解Object-C这门语言。假如您觉着这篇文章对您有所帮助,请别吝啬您的手指,左下方点个赞,谢谢!

上一篇下一篇

猜你喜欢

热点阅读