思考, 如何實現給分類"添加成員變量"?
默認情況下, 因為分類底層結構的限制, 不能添加成員變量到分類中. 但可以通過關聯對象來間接實現
關聯對象提供了以下API
- 添加關聯對象
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)
Key
的常見用法
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)
static char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)
使用屬性名作為key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_getAssociatedObject(obj, @"property");
使用get
方法的@selecor
作為key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, @selector(getter))
或者用
objc_getAssociatedObject(self, _cmd)
一般用第四種: 使用get
方法的@selecor
作為key
再來看一下: objc_AssociationPolicy
我們看下objc_setAssociatedObject
底層究竟做了些什么:
直接調用了_object_set_associative_reference
:
所以, 這個數據存儲的流程就是:
運行時全局維護了一個AssociationsManager
管理類, 那么這個管理類里又有一個AssociationsHashMap
這個AssociationsHashMap
是通過object
為key存儲數據的, 也就是說, 一個對象對應一條數據, 那么每個關聯的對象都對應一條數據.
這條數據就又是一個hashMap
, 即: ObjectAssociationMap
那么ObjectAssociationMap
里面又是什么呢?
ObjectAssociationMap
以你傳入的key
為key
, 值是由你傳入的policy
和value
組成的結構體為值
如下圖所示:
如果設置value
為nil
, 會移除掉這個key嗎?
如果通過
key
找到了, 就會直接刪除這個value
, 如果整個關聯對象中已經不存在需要關聯的值, 那就會把整個關聯對象都刪掉.
我們再來看看objc_getAssociatedObject
內部調用了_object_get_associative_reference
可以很清楚的看到邏輯:
先通過
object
, 找到associations
這個hashmap
里的值, 也是一個hashmap
, 叫做ObjectAssociationMap
再通過
key
找到refs
里的值, 就是association
, 里面存儲了policy
和value
值, 最后返回的是association
里的autoreleaseReturnedValue
值.
而移除所有關聯對象, objc_removeAssociatedObjects
就是根據object
為key
, 找到對應的hashMap
, 然后再刪掉, 如下圖所示: