分类不能直接添加成员变量,可以通过关联对象间接达到添加成员变量的效果,不能添加成员变量是由于分类的底层结构体是这样的
分类里面有实例方法列表、类方法列表、协议列表、实例属性列表、类属性列表,没有成员变量列表,类似ivars的变量,所以分类中不能添加成员变量,下面通过代码看下
上图可以看出,给类WPPerson添加了一个分类,然后定义了一个name属性,在getter方法中使用_name成员变量是报错的
其实也可以手动实现有成员变量的假象,让外部使用起来没有什么感觉,做法是定义一个全局字典,将外部调用setter方法传进来的数据保存在字典中,大家可以自己尝试下。
下面说下关联对象的使用,关联对象主要是通过调用两个方法来实现
先说下这几个参数:
参数1:需要关联的对象,传self
参数2:key,这是一个void*,所以传一个地址进去
参数3:value,外部传入的值
参数4:关联存储策略,和我们平时修饰属性时一样,copy,strong,assign,nonatomic。。。
用法很简单,由于在分类中添加属性,系统只会生成该属性的setter和getter方法的申明,所以需要自己写实现
这样外部在使用时和在类里面定义的属性就没有什么区别,但底层实现和直接在类里面定义的属性是不一样的,下面通过源码看下关联对象的底层实现
主要实现在_object_set_associative_reference方法里面,先说下这几个类的关系
AssociationsManager结构 AssociationsHashMap结构 ObjectAssociationMap结构 ObjectAssociation结构AssociationsManager:管理者
AssociationsHashMap:里面存储着所有关联对象的信息,一个键值就是一个关联对象的信息(WPPerson、WPCat。。。)
AssociationsHashMap:里面存储着当前WPPerson关联对象的所有关联属性信息,一个键值就是一个属性信息(name、age。。)
ObjectAssociation:里面存储着当前属性的关联策略以及具体的值
这样一层层的就能找到对应的关联信息,比如我们想获取WPPerson的name属性的值时,先找到AssociationsManager里面的AssociationsHashMap,再通过WPPerson的实例作为key从AssociationsHashMap找到对应的value也就是AssociationsHashMap,再通过name的key也就是@selector(name)最为key从AssociationsHashMap中找到ObjectAssociation,这样就能拿到name属性的具体值了
下面给源码添加了注释
清除关联对象只需要调用方法的时候将value传入nil即可
所以关联对象底层其实是用一个全局的hashMap将self与所谓的成员变量保存起来,并不是存在类对象或者元类对象里面
网友评论