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这门语言。假如您觉着这篇文章对您有所帮助,请别吝啬您的手指,左下方点个赞,谢谢!