category添加成员变量(关联对象)及原理

实现

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_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 

- (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
image.png
objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy);

AssociationsManager维护着一张AssociationsHashMap结构的HashMap,以objc_setAssociatedObject中第一个参数[object]作为key,找出对应的ObjectAssociationMapObjectAssociationMap也是一个Map,以我们传递的第二个参数[key]作为key,找出对应的ObjcAssociation(当我们这个key传递为nil,将删除ObjcAssociation键值对),这个ObjcAssociation里面维护着两个参数,就是我们传递的后两个参数:[value]、[policy]。取值的时候就通过两个key,找出对应的值

总结

category添加成员变量的实现,实际上是通过一个双重Map来存储将要存储的属性值,第一层Map维护各个category分类的添加成员变量的实现,第二层Map,维护这个category中的成员变量赋值操作。

你可能感兴趣的:(category添加成员变量(关联对象)及原理)