- 關(guān)聯(lián)對象的使用場合
- 關(guān)聯(lián)對象的基本使用
- 關(guān)聯(lián)對象的底層原理
一、關(guān)聯(lián)對象的使用場合
默認情況下,因為分類底層結(jié)構(gòu)的限制,不能添加成員變量到分類中,但可以通過關(guān)聯(lián)對象來間接實現(xiàn)。
關(guān)聯(lián)對象提供了以下API:
// 1.添加關(guān)聯(lián)對象:
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
// 2.獲得關(guān)聯(lián)對象:
id objc_getAssociatedObject(id object, const void * key)
// 3.移除所有的關(guān)聯(lián)對象
void objc_removeAssociatedObjects(id object)
在添加關(guān)聯(lián)對象的方法中有一個policy屬性,它是一個枚舉值,對應(yīng)我們平時定義屬性時設(shè)置的修飾詞:

二、關(guān)聯(lián)對象的基本使用
使用關(guān)聯(lián)對象需要#import <objc/runtime.h>
// 給DJTPerson創(chuàng)建一個分類,添加一個name屬性
@interface DJTPerson (Test)
@property (nonatomic, copy) NSString *name;
@end
@implementation DJTPerson (Test)
/**
* 第一種寫法:創(chuàng)建一個void*類型的指針作為key,它存著自己的地址,只要唯一就行
*/
static const void *DJTNameKey = &DJTNameKey;
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, DJTNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, &DJTNameKey);
}
/**
* 第二種寫法:既然是void*類型,使用char類型的地址,節(jié)省空間
*/
static const char DJTNameKey;
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, &DJTNameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, &DJTNameKey);
}
/**
* 第三種寫法:使用屬性名作為key,其實也是傳的內(nèi)存地址
*/
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @"name");
}
/**
* 第四種寫法:使用get方法的@selector作為key,這種寫法的好處是它返回的是一個結(jié)構(gòu)體指針,寫錯方法名會有錯誤提示
*/
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
//@selector(name)等價于隱式參數(shù)_cmd
return objc_getAssociatedObject(self, @selector(name));
// return objc_getAssociatedObject(self, _cmd);
}
@end
三、關(guān)聯(lián)對象的底層原理
關(guān)聯(lián)對象并不是存儲在被關(guān)聯(lián)對象本身的內(nèi)存中,通過分析底層實現(xiàn),它存儲在由AssociationsManager管理的全局統(tǒng)一的一個AssociationsHashMap中,關(guān)系如下:

從上圖可以看出,關(guān)聯(lián)對象的底層實現(xiàn)依賴下面四個核心對象:
AssociationsManagerAssociationsHashMapObjectAssociationMapObjectionAssociation
它們之間的關(guān)系:AssociationsHashMap里存儲著某個對象的關(guān)聯(lián)對象Map表,即ObjectAssociationMap,這個表存儲了多個關(guān)聯(lián)對象,因為在分類里可以給對象添加多個屬性,也就要設(shè)置多個關(guān)聯(lián)對象,ObjectAssociationMap中就是我們添加的關(guān)聯(lián)對象,比如name,由ObjectionAssociation存儲值和策略,當我們將關(guān)聯(lián)對象(即value值,本例中是person.name = nil)設(shè)為nil時,AssociationsMap自動刪除這條關(guān)聯(lián)對象;當我們調(diào)用objc_removeAssociatedObjects(id object)方法時,就是移除某個對象的所有關(guān)聯(lián)對象,即上圖中AssociationHashMap需要移除對象的關(guān)聯(lián)對象Map表;