Runtime初探(二)

关联对象

在分类中可以定义property,但是编译器并不会@synthesize实例变量。一般有需求添加实例变量属性时会采用objc_setAssociatedObjectobjc_getAssociatedObject方法绑定方法绑定,不过这种方法生成的与一个普通的实例变量完全是两码事。

objc_setAssociatedObject

分析源码后发现苹果为分类的属性建造了一个大的hashmap,这个大的hashmap的里面又根据对象划分了多个子hashmap,划分的依照object来划分。每个子hashmap中存放了各个分类添加的属性。

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

发现内部调用了_object_set_associative_reference

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
if (!object && !value) return; //如果没有 需要被关联的对象和值则返回

ObjcAssociation old_association(0, nil); // 旧值
id new_value = value ? acquireValue(value, policy) : nil; // 新值
{
AssociationsManager manager; // 全局管理关联的单例
AssociationsHashMap &associations(manager.associations()); // 通过单例获取 hashmap
disguised_ptr_t disguised_object = DISGUISE(object); // 根据对象生成唯一 key
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);
}

_object_get_associative_reference

取值比较简单,就是根据key和object对象进行遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
id _object_get_associative_reference(id object, void *key) {
id value = nil;
uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
disguised_ptr_t disguised_object = DISGUISE(object);
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()) {
ObjcAssociation &entry = j->second;
value = entry.value();
policy = entry.policy();
if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {
objc_retain(value);
}
}
}
}
if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
objc_autorelease(value);
}
return value;
}