一、思考:如何實現給分類“添加成員變量”?
-
默認情況下,因爲分類底層結構的限制,不能添加成員變量到分類中。但可以通過關聯對象來間接實現
-
關聯對象提供了以下API
// 添加關聯對象
/*
id object: 要關聯的對象
const void * key: 關聯屬性的key
id value: 要關聯的屬性值
objc_AssociationPolicy policy: 策略
*/
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的常見用法
- 方式一: 使用指針變量作爲key
// 爲啥使用static, 不要用全局的指針變量, 外界可以修改, 導致數據出錯
static void *MyKey = &MyKey;
objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, MyKey)
- 方式二: 使用常量的地址作爲key
// 爲啥用char, 因爲char類型的常量只有1個字節
static const char MyKey;
objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
objc_getAssociatedObject(obj, &MyKey)
- 方式三: 使用屬性名作爲key
objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_getAssociatedObject(obj, @"property");
- 方式四(推薦):使用get方法的@selecor作爲key
objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
// _cmd == @selector(getter)
// objc_getAssociatedObject(obj, @selector(getter))
objc_getAssociatedObject(self, _cmd);
三、objc_AssociationPolicy
四、關聯對象的原理
-
實現關聯對象技術的核心對象有
- AssociationsManager
- AssociationsHashMap
- ObjectAssociationMap
- ObjcAssociation
-
objc4源碼解讀:objc-references.mm
五、關聯對象的原理
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
- 關聯對象並不是存儲在被關聯對象本身內存中
- 關聯對象存儲在全局的統一的一個AssociationsManager中
- 設置關聯對象爲nil,就相當於是移除關聯對象