#import "Duck.h"
@interface Duck (associative)
@property (nonatomic, retain) NSString *color;
@end
Duck+associative.m文件#import "Duck+associative.h"
#import <objc/runtime.h>
@implementation Duck (associative)
static char colorKey = NULL;
- (NSString *)color {
return objc_getAssociatedObject(self, &colorKey);
}
- (void)setColor:(NSString *)aColor {
objc_setAssociatedObject(self, &colorKey,
aColor,
OBJC_ASSOCIATION_RETAIN);
}
Duck *smallDuck = [[Duck alloc] init];
smallDuck.color = @"red color";
NSLog(@"duck color:%@",smallDuck.color);
[smallDuck release];
2013-07-18 19:09:26.578 ObjcRunTime[429:403] duck color:red color
二、爲類動態增加屬性用到的技術
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy) {
if (UseGC) {
//這部分是有垃圾回收機制的實現,我們不用管
if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
value = objc_msgSend(value, @selector(copy));
}
auto_zone_set_associative_ref(gc_zone, object, key, value);
} else {
//這是引用計數機制部分的實現
// Note, creates a retained reference in non-GC.
_object_set_associative_reference(object, key, value, policy);
}
}
__private_extern__ void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
// retain the new value (if any) outside the lock.
uintptr_t old_policy = 0;
// NOTE: old_policy is always assigned to when old_value is non-nil.
id new_value = value ? acquireValue(value, policy) : nil, old_value = nil;
{
AssociationsManager manager;
AssociationsHashMap &associations(manager.associations());
if (new_value) {
//如果new_value不爲空,開始遍歷associations指向的map,查找object對象是否存在保存聯合存儲數據的ObjectAssociationMap對象
// break any existing association.
AssociationsHashMap::iterator i = associations.find(object);
if (i != associations.end()) {
//object對象在associations指向的map中存在一個ObjectAssociationMap對象refs
//檢查refs中是否使用key保存過value
// secondary table exists
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
//使用過該key保存value,用新的value和policy替換掉原來的值
ObjcAssociation &old_entry = j->second;
old_policy = old_entry.policy;
old_value = old_entry.value;
old_entry.policy = policy;
old_entry.value = new_value;
} else {
//沒用使用過該key保存value,將value和policy保存到key映射的map中
(*refs)[key] = ObjcAssociation(policy, new_value);
}
} else {
// object對象在associations指向的map中不存在一個ObjectAssociationMap對象
// 則新建一個ObjectAssociationMap對象,並將new_value通過key的地址映射到該map中保存
// create the new association (first time).
ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
_class_assertInstancesHaveAssociatedObjects(object->isa);//通知object對象,綁定了一個新的值
}
} else {
//new_value爲空,如果使用過該key保存過value,則解除使用該key保存的value值
// setting the association to nil breaks the association.
AssociationsHashMap::iterator i = associations.find(object);
if (i != associations.end()) {
ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
ObjcAssociation &old_entry = j->second;
old_policy = old_entry.policy;
old_value = (id) old_entry.value;
refs->erase(j);
}
}
}
}
// release the old value (outside of the lock).
if (old_value) releaseValue(old_value, old_policy);
}
3、通過這個方法的實現部分可以清楚的看出,在runtime系統中:①有一個單例的AssociationsHashMap實例
AssociationsHashMap &associations() {
if (_map == NULL)
_map = new(::_malloc_internal(sizeof(AssociationsHashMap))) AssociationsHashMap();
return *_map;
}
②AssociationsHashMap實例用於保存一個個的ObjectAssociationMap對象static char colorKey = NULL;