- 關聯(lián)對象的使用場合
- 關聯(lián)對象的基本使用
- 關聯(lián)對象的底層原理
一、關聯(lián)對象的使用場合
默認情況下,因為分類底層結構的限制遵班,不能添加成員變量到分類中,但可以通過關聯(lián)對象來間接實現(xiàn)潮改。
關聯(lián)對象提供了以下API
:
// 1.添加關聯(lián)對象:
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
// 2.獲得關聯(lián)對象:
id objc_getAssociatedObject(id object, const void * key)
// 3.移除所有的關聯(lián)對象
void objc_removeAssociatedObjects(id object)
在添加關聯(lián)對象的方法中有一個policy
屬性狭郑,它是一個枚舉值,對應我們平時定義屬性時設置的修飾詞:
二汇在、關聯(liá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雳锋,這種寫法的好處是它返回的是一個結構體指針,寫錯方法名會有錯誤提示
*/
- (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
三羡洁、關聯(lián)對象的底層原理
關聯(lián)對象并不是存儲在被關聯(lián)對象本身的內(nèi)存中玷过,通過分析底層實現(xiàn),它存儲在由AssociationsManager
管理的全局統(tǒng)一的一個AssociationsHashMap
中焚廊,關系如下:
從上圖可以看出,關聯(lián)對象的底層實現(xiàn)依賴下面四個核心對象:
AssociationsManager
AssociationsHashMap
ObjectAssociationMap
ObjectionAssociation
它們之間的關系:AssociationsHashMap
里存儲著某個對象的關聯(lián)對象Map
表习劫,即ObjectAssociationMap
咆瘟,這個表存儲了多個關聯(lián)對象,因為在分類里可以給對象添加多個屬性诽里,也就要設置多個關聯(lián)對象袒餐,ObjectAssociationMap
中就是我們添加的關聯(lián)對象,比如name
,由ObjectionAssociation
存儲值和策略灸眼,當我們將關聯(lián)對象(即value
值卧檐,本例中是person.name = nil
)設為nil
時,AssociationsMap
自動刪除這條關聯(lián)對象焰宣;當我們調(diào)用objc_removeAssociatedObjects(id object)
方法時霉囚,就是移除某個對象的所有關聯(lián)對象,即上圖中AssociationHashMap
需要移除對象的關聯(lián)對象Map
表匕积;