關(guān)聯(lián)對象

分類中不能添加成員變量

默認(rèn)情況下,因?yàn)榉诸惖讓咏Y(jié)構(gòu)的限制,分類中不能添加成員變量。如果強(qiáng)行添加會報(bào)錯(cuò)“Instance variables may not be placed in categories實(shí)例變量不能放在類別中實(shí)例變量不能放在類別中”如下圖

image.png

如果通過@property (assign, nonatomic) int a;不會添加成員變量,只會生成(沒有實(shí)現(xiàn)設(shè)值和取值)的setter和getter方法.

通過關(guān)聯(lián)對象變相的給分類“添加成員變量”

設(shè)置關(guān)聯(lián)對象

objc_setAssociatedObject(id object, const void * key,
                         id value, objc_AssociationPolicy policy)

獲取關(guān)聯(lián)對象

objc_getAssociatedObject(id object, const void * key)

移除類所有的關(guān)聯(lián)對象

objc_removeAssociatedObjects(id object)

key的常見用法,保證key的唯一性

取唯一的指針地址值
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)
static NSString *MyKey1;
objc_setAssociatedObject(obj, &MyKey1, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey1)
使用屬性名作為key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");
使用get方法的方法編號@selecor作為key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))

objc_AssociationPolicy

OBJC_ASSOCIATION_ASSIGN//assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC//strong,nonatomic
OBJC_ASSOCIATION_COPY_NONATOMIC//copy, nonatomic
OBJC_ASSOCIATION_RETAIN//strong,atomic
OBJC_ASSOCIATION_COPY//copy,atomic
關(guān)聯(lián)對象的原理

objc4源碼解讀`objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
    _object_set_associative_reference(object, (void *)key, value, policy);
}
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // 初始化第三個(gè)表。
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        第一個(gè)表AssociationsHashMap
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);//object作為key
        if (new_value) {
  
            //通過disguised_object取value值ObjectAssociationMap
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {//i不是最后一個(gè)
                // 第二個(gè)表ObjectAssociationMap類表
                ObjectAssociationMap *refs = i->second;
                //ObjectAssociationMap對象表中通過key取出value值ObjcAssociation
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {//j不是最后一個(gè)
                     //第三個(gè)表,ObjcAssociation類表
                    old_association = j->second;
                    //第三個(gè)表設(shè)置新值
                    j->second = ObjcAssociation(policy, new_value);
                } else {
                    (*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 {
            // 設(shè)置關(guān)聯(lián)為nil會移除關(guān)聯(lián)值。
            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);
}

實(shí)現(xiàn)關(guān)聯(lián)對象技術(shù)的核心對象有

AssociationsManager
AssociationsHashMap//類表1
ObjectAssociationMap//類表2
ObjcAssociatio//類表3

class AssociationsManager {
    static AssociationsHashMap *_map
};
類表1
class AssociationsHashMap : public unordered_map<disguised_ptr_t(key), ObjectAssociationMap *(value)>
類表2
class ObjectAssociationMap : public std::map<void *(key), ObjcAssociation(value)>
類表3
class ObjcAssociation {
        uintptr_t _policy;//key
        id _value;//value
};

objc4源碼解讀:objc-references.mm

原理圖解:
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容