如何为分类(Category)添加成员变量

关联对象涉及的三个方法

id objc_getAssociatedObject(id object, const void *key) {
    return _object_get_associative_reference(object, (void *)key);
}


void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
    _object_set_associative_reference(object, (void *)key, value, policy);
}


void objc_removeAssociatedObjects(id object) 
{
    if (object && object->hasAssociatedObjects()) {
        _object_remove_assocations(object);
    }
}

关联对象的本质

  • 关联对象是由AssociationsManager管理并存储在AssociationsManager中
  • 所有对象的关联内容都是存储在同一个全局容器中
如何为分类(Category)添加成员变量_第1张图片
关联对象.png

源码分析

/**
 * 关联对象
 * @param object
 * @param key
 * @param value 值
 * @param policy 策略
 * @by Si
 */
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // This code used to work when nil was passed for object and key. Some code
    // probably relies on that to not crash. Check and handle it explicitly.
    // rdar://problem/44094390
    if (!object && !value) return;
    
    assert(object);
    
    if (object->getIsa()->forbidsAssociatedObjects())
        _objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object));
    
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    // 获取新的值
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        // 关联对象管理类
        AssociationsManager manager;
        AssociationsManagerAssociationsManager &associations(manager.associations());
        // 按位取反,作为关联对象的key
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            // 获取其维护的一个HashMap,是一个全局容器
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            // 当前对象存在
            if (i != associations.end()) {
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                // key存在直接赋值
                if (j != refs->end()) {
                    old_association = j->second;
                    j->second = ObjcAssociation(policy, new_value);
                } else {
                    // 不存在则生成一个ObjcAssociation
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                }
            } else {
                // create the new association (first time).
                ObjectAssociationMap *refs = new ObjectAssociationMap;
                associations[disguised_object] = refs;
                (*refs)[key] = ObjcAssociation(policy, new_value);
                object->setHasAssociatedObjects();
            }
        } else {
            // setting the association to nil breaks the association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i !=  associations.end()) {
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    refs->erase(j);
                }
            }
        }
    }
    // release the old value (outside of the lock).
    if (old_association.hasValue()) ReleaseValue()(old_association);
}

关联对象的结构

如何为分类(Category)添加成员变量_第2张图片
关联对象的结构图.png

你可能感兴趣的:(如何为分类(Category)添加成员变量)