关联对象
能否给分类添加"成员变量"?
使用关联对象技术为分类添加"成员变量"
关联对象添加的"成员变量"添加到了那里?
关联对象的本质
关联对象由系统提供的AssociationsManager
类管理并在其成员变量AssociationsHashMap
中存储。
所有对象的关联内容都在同一个全局容器中(不同的类添加的分类成员变量也是放在这里)。
关联对象的本质.png源码解析
源码是objc-runtime.mm
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);
}
}
static id acquireValue(id value, uintptr_t policy) {
//根据policy决定消息发送的类型
switch (policy & 0xFF) {
case OBJC_ASSOCIATION_SETTER_RETAIN:
return objc_retain(value);
case OBJC_ASSOCIATION_SETTER_COPY:
return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
}
return value;
}
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;//见上面函数实现
{
//关联对象管理类,C++实现的一个类
AssociationsManager manager;
//获取其维护的一个Hashmap,我们可以理解为是一个字典
//=============
//是一个全局对象
//=============
AssociationsHashMap &associations(manager.associations());
//DISGUISE函数对指针地址进行按位取反~,来作为全局容器当中某个对象的key
//inline disguised_ptr_t DISGUISE(id value) { return ~uintptr_t(value); }
disguised_ptr_t disguised_object = DISGUISE(object);
if (new_value) {//value不为空
// break any existing association.
//根据对象指针查找对应的一个ObjectAssociationMap结构的Map
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 {//value为空
// 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); //擦除
//如果想撤销一个已经关联到对象的一个值时,可以采取value传值为nil的方式来实现
}
}
}
}
// release the old value (outside of the lock).
if (old_association.hasValue()) ReleaseValue()(old_association);
}
关联对象的本质02.png
网友评论