Category是Objective C为程序员提供的一个强大的动态机制,它们允许程序员为已有的对象添加新的方法,即便是在没有该对象的源代码的情况下。通过它可以很方便的为已有的类来添加函数。但是Category不允许为已有的类添加新的属性或者成员变量。
通过运行时的数据结构我们可以看到,objc_class结构体中维护着objc_ivar_list的指针,这个指针指向的是类中定义的实例变量的列表。
再看看objc_category
的结构体中,只有类别名,类名,实例方法,类方法和遵循的协议表,由此可以看出category类中是不能够添加成员变量的。
可以发现,苹果的category设计明显是不允许在category中添加新的成员变量。但是在项目中,这明显不能满足我们的需求,不过值得庆幸的是,我们可以通过Associated Objects来弥补这一不足。
Associated Objects 介绍
与 Associated Objects 相关的函数主要有三个,我们可以在 runtime.h 文件中找到它们的声明:
代码语言:javascript复制1. void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
2. id objc_getAssociatedObject(id object, const void *key)
3. void objc_removeAssociatedObjects(id object)
Object
:传入关联对象的所属对象,也就是增加成员的实例对象,一般来说传入self。
key
:一个唯一标记。在官方文档中推荐使用static char,当然更推荐是指针。为了便捷,一般使用selector,这样在后面getter中,我们就可以利用_cmd来方便的取出selector。
value
:传入关联对象。
policy
:objc_AssociationPolicy是一个ObjC枚举类型,也代表关联策略。
Associated Objects 源码浅析
那究竟关联对象是如何存储的呢?透过源码,我们看到关联对象是通过一个叫做AssociationsManager
的对象来进行管理的。
在AssociationsManager中,有一个spinlock_t
锁和一个AssociationsHashMap
的哈希表。
然后再看objc_setAssociatedObject
的源码,我们可以看懂啊AssociationsHashMap
中的键为disguised_ptr_t
,在得到这个指针的时候,源码中执行了DISGUISE
方法,通过这个方法能够获得指向self地址的指针,即为指向对象地址的指针。然后其对应的value,便是一个存放关联对象的子哈希表。