实现
category
无法添加成员变量,category
编译之后,会生成struct _category_t
类型的结构体,包含instance_methods
(对象方法列表),class_methods
(类方法列表),protocols
(协议列表),properties
(属性列表),没有类似ivars
这样的成员变量列表
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
不过我们可以通过设置关联对象的方式添加属性,当我们#import <objc/runtime.h>
之后,可以通过如下方法
OBJC_EXPORT void
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy);
OBJC_EXPORT id _Nullable
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key);
OBJC_EXPORT void
objc_removeAssociatedObjects(id _Nonnull object);
其中objc_AssociationPolicy
为如下结构,分别对应不同的属性声明(由于关联对象是通过全局Map
维护,所以没有weak声明)
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
实现方式为:
// .h文件
@property (nonatomic, copy) NSString *name;
// .m文件
#import <objc/runtime.h>
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, @selector(name));
}
原理
通过查看objc_setAssociatedObject
源码得知,有一个AssociationsManager
管理关联对象,其结构部署为:
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjcAssociation
objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy);
AssociationsManager
维护着一张AssociationsHashMap
结构的HashMap
,以objc_setAssociatedObject
中第一个参数[object
]作为key
,找出对应的ObjectAssociationMap
,ObjectAssociationMap
也是一个Map
,以我们传递的第二个参数[key
]作为key
,找出对应的ObjcAssociation
(当我们这个key
传递为nil
,将删除ObjcAssociation
键值对),这个ObjcAssociation
里面维护着两个参数,就是我们传递的后两个参数:[value
]、[policy
]。取值的时候就通过两个key
,找出对应的值
总结
category
添加成员变量的实现,实际上是通过一个双重Map
来存储将要存储的属性值,第一层Map
维护各个category
分类的添加成员变量的实现,第二层Map
,维护这个category
中的成员变量赋值操作。