OC關(guān)聯(lián)對(duì)象小結(jié)(一)
使用場(chǎng)景
為現(xiàn)有的類添加屬性蒲肋,變量
在Objective-C中可以通過Category給一個(gè)現(xiàn)有的類添加屬性(如NSObject),但是卻不能添加實(shí)例變量忱嘹,然而可以通過Associated Object間接地達(dá)到這一目的。示例代碼展示了給NSObject添加實(shí)例變量。
為KVO
創(chuàng)建一個(gè)關(guān)聯(lián)的觀察者
相關(guān)函數(shù)
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void *key);
void objc_removeAssociatedObjects(id object);
objc_setAssociatedObject
用于給對(duì)象添加關(guān)聯(lián)對(duì)象仍律,傳nil
可以移除相關(guān)的關(guān)聯(lián)對(duì)象。
objc_getAssocicatedObject
用于獲取關(guān)聯(lián)對(duì)象的值实柠。
objc_removeAssociatedObject
用于移除該對(duì)象的所有關(guān)聯(lián)對(duì)象水泉。如果打算只移除一部分則不能使用該方法。
相關(guān)參數(shù)
key:要保證全局唯一窒盐,key與關(guān)聯(lián)的對(duì)象是一一對(duì)應(yīng)關(guān)系草则。必須全局唯一。通常用@selector(methodName)
作為key蟹漓。
value:要關(guān)聯(lián)的對(duì)象炕横。
policy:關(guān)聯(lián)策略。有五種關(guān)聯(lián)策略葡粒。
OBJC_ASSOCIATION_ASSIGN
等價(jià)于 @property(assign)
份殿。
OBJC_ASSOCIATION_RETAIN_NONATOMIC
等價(jià)于 @property(strong, nonatomic)
。
OBJC_ASSOCIATION_COPY_NONATOMIC
等價(jià)于@property(copy, nonatomic)
嗽交。
OBJC_ASSOCIATION_RETAIN
等價(jià)于@property(strong,atomic)
卿嘲。
OBJC_ASSOCIATION_COPY
等價(jià)于@property(copy, atomic)
。
原理簡介
運(yùn)行時(shí)通過map維系一張關(guān)聯(lián)對(duì)象與被關(guān)聯(lián)對(duì)象之間的關(guān)系夫壁。
objc_setAssociatedObject
的相關(guān)代碼.
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
ObjcAssociation old_association(0, nil);
id new_value = value ? acquireValue(value, policy) : nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
if (new_value) {
// break any existing association.
AssociationsHashMap::iterator i = associations.find(disguised_object);
if (i != associations.end()) {
// secondary table exists
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
old_association = j->second;
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 {
// 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);
}
代碼中涉及到的一些數(shù)據(jù)結(jié)構(gòu)拾枣。
- AssociationsManager 是頂級(jí)的對(duì)象,維護(hù)了一個(gè)從 spinlock_t 鎖到 AssociationsHashMap 哈希表的單例鍵值對(duì)映射掌唾;
- AssociationsHashMap 是一個(gè)無序的哈希表放前,維護(hù)了從對(duì)象地址到 ObjectAssociationMap 的映射;
- ObjectAssociationMap 是一個(gè) C 中的 map 糯彬,維護(hù)了從 key 到 ObjcAssociation 的映射凭语,即關(guān)聯(lián)記錄;
-
ObjcAssociation 是一個(gè) C 的類撩扒,表示一個(gè)具體的關(guān)聯(lián)結(jié)構(gòu)似扔,主要包括兩個(gè)實(shí)例變量吨些,_policy 表示關(guān)聯(lián)策略,_value 表示關(guān)聯(lián)對(duì)象炒辉。
流程圖如下:
看懂這個(gè)豪墅,那其他的幾個(gè)也就懂了。