##oc在類別裡給類加屬性以及原理,
oc在類別裡給類加屬性以及原理
如何在類別裡給類加屬性呢,有鴨子模樣的我們就認為他是鴨子了.
@interface NSObject (XY)@property (nonatomic, strong) id tempObject;@end@implementation NSObject (XY)@dynamic tempObject;- (id)tempObject- { id object = objc_getAssociatedObject(self, NSObject_key_tempObject); return object;}- (void)setTempObject:(id)tempObject- { [self willChangeValueForKey:@"tempObject"]; objc_setAssociatedObject(self, NSObject_key_tempObject, tempObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [self didChangeValueForKey:@"tempObject"];}@end
屬性取變數是直接位移地址得到,關聯是取了2次map.
下面來看一下set get 還有dealloc時候發生的事情吧
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {#if SUPPORT_GC if (UseGC) { if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) { value = objc_msgSend(value, SEL_copy); } auto_zone_set_associative_ref(gc_zone, object, (void *)key, value); } else #endif { // Note, creates a retained reference in non-GC. _object_set_associative_reference(object, (void *)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) { // 如果有值 // break any existing association. AssociationsHashMap::iterator i = associations.find(object); if (i != associations.end()) { // 如果在map裡有object的話 // secondary table exists ObjectAssociationMap *refs = i->second; ObjectAssociationMap::iterator j = refs->find(key); if (j != refs->end()) { // 如果在ObjectAssociationMap裡沒找到key對應的值就new一個,塞進去 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 { // 找到了就直接賦值 (*refs)[key] = ObjcAssociation(policy, new_value); } } else { // 沒有object就建立 // create the new association (first time). ObjectAssociationMap *refs = new ObjectAssociationMap; associations[object] = refs; (*refs)[key] = ObjcAssociation(policy, new_value); _class_setInstancesHaveAssociatedObjects(_object_getClass(object)); } } else { // 沒值就清空 // 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);}id objc_getAssociatedObject(id object, const void *key) {#if SUPPORT_GC if (UseGC) { return auto_zone_get_associative_ref(gc_zone, object, (void *)key); } else #endif { return _object_get_associative_reference(object, (void *)key); }}PRIVATE_EXTERN id _object_get_associative_reference(id object, void *key) { id value = nil; uintptr_t policy = OBJC_ASSOCIATION_ASSIGN; { AssociationsManager manager; AssociationsHashMap &associations(manager.associations()); AssociationsHashMap::iterator i = associations.find(object); if (i != associations.end()) { // 取值的時候就在AssociationsHashMap裡面先找到object ObjectAssociationMap *refs = i->second; ObjectAssociationMap::iterator j = refs->find(key); if (j != refs->end()) { // 然後找到的key對應的值 ObjcAssociation &entry = j->second; value = (id)entry.value; policy = entry.policy; if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) objc_msgSend(value, SEL_retain); } } } if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) { objc_msgSend(value, SEL_autorelease); } return value;}void *objc_destructInstance(id obj) { if (obj) { Class isa = _object_getClass(obj); if (_class_hasCxxStructors(isa)) { object_cxxDestruct(obj); } // 在釋放的代碼裡,釋放關聯的屬性 if (_class_instancesHaveAssociatedObjects(isa)) { _object_remove_assocations(obj); } if (!UseGC) objc_clear_deallocating(obj); } return obj;}