關(guān)聯(lián)引用:能夠?qū)⒛硞€(gè)對象作為value通過唯一的key與另一個(gè)對象進(jìn)行關(guān)聯(lián),作為value的對象可以看作是另一對象的一部分。能夠讓開發(fā)者給使用category的類中添加自定義屬性。
關(guān)聯(lián)對象(associated object):在runtime函數(shù)中作為關(guān)聯(lián)值(associated value),例如將對象b作為關(guān)聯(lián)對象(或關(guān)聯(lián)值)與對象a以key值進(jìn)行關(guān)聯(lián)
NSObject a = [[NSObject alloc]init];
NSObject b = [[NSObject alloc]init];
objc_setAssociatedObject(a, key, b, OBJC_ASSOCIATION_ASSIGN);
runtime與關(guān)聯(lián)引用有關(guān)的方法
-
創(chuàng)建關(guān)聯(lián)引用
/** * 通過給定的key和關(guān)聯(lián)策略,為給定對象創(chuàng)建一個(gè)關(guān)聯(lián)value * @param object 進(jìn)行關(guān)聯(lián)操作的源對象The source object for the assciation. * @param key 關(guān)聯(lián)引用需要的key值. * @param value 與Key值關(guān)聯(lián)的value,value為nil,可清除已存在的關(guān)聯(lián) * @param policy關(guān)聯(lián)策略 **/ void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) -
獲取關(guān)聯(lián)對象
/** * 按照給定對象和給定key返回關(guān)聯(lián)的value * @param object 關(guān)聯(lián)操作的源對象 * @param key 關(guān)聯(lián)操作的key. * @return 通過key與對象進(jìn)行關(guān)聯(lián)的value. */ id objc_getAssociatedObject(id object, const void *key) -
移除關(guān)聯(lián)引用
/** * 移除對象所有的關(guān)聯(lián)引用 * @param object 具有關(guān)聯(lián)引用的對象. * @note 這個(gè)函數(shù)的目的是為了方便獲取給定對象的沒有任何關(guān)聯(lián)引用原始狀態(tài)。 * 不應(yīng)該用這個(gè)函數(shù)移除某個(gè)value與對象的關(guān)聯(lián)引用,因?yàn)檫@樣也會(huì)移除這個(gè)對 * 象與其它對象的關(guān)聯(lián)引用。通常,應(yīng)使用objc_setAssociatedObject,傳入 * nil的value來清除對象與某個(gè)已存在的value的關(guān)聯(lián)引用 */ void objc_removeAssociatedObjects(id object)
關(guān)聯(lián)策略(objc_AssociationPolicy)
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< 指定關(guān)聯(lián)對象的弱引用 */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< 指定關(guān)聯(lián)對象的非原子性的強(qiáng)引用*/
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< 指定關(guān)聯(lián)對象為copy類型并且非原子性*/
OBJC_ASSOCIATION_RETAIN = 01401, /**< 指定關(guān)聯(lián)對象為原子性強(qiáng)引用*/
OBJC_ASSOCIATION_COPY = 01403 /**< 指定關(guān)聯(lián)對象為原子性的copy*/
};
關(guān)聯(lián)引用的使用方式
- 添加私有成員變量
- 給category添加公共屬性
- 為KVO創(chuàng)建關(guān)聯(lián)的觀察者對象:當(dāng)在category中使用KVO時(shí),推薦使用自定義的關(guān)聯(lián)對象作為觀察者,可以參考文章Objective-C Associated Objects
示例:在category中添加屬性
-
.h文件
@interface NSObject (Custom) { // NSString *str0; //使用category的類中不能添加成員變量 } @property (nonatomic, strong) NSString *str1; @end -
.m文件
#import "NSObject+Custom.h" #import <objc/runtime.h> @implementation NSObject (Custom) @dynamic str1; //這里使用@dynamic告訴編譯器在編譯期間不要自動(dòng)創(chuàng)建屬性的存取方法,也可以不用寫(因?yàn)榭梢詫ν姆椒ㄟM(jìn)行override) //定義key值,一般為靜態(tài)char類型,最簡便的方式就是用SEL類型作為key值 //static char key; - (void)setStr1:(NSString *)str1 { // objc_setAssociatedObject(self, &key, str1, OBJC_ASSOCIATION_COPY_NONATOMIC); //用SEL代替static char的key objc_setAssociatedObject(self, @selector(str1), str1, OBJC_ASSOCIATION_COPY); } - (NSString *)str1 { // return objc_getAssociatedObject(self, &key); //用SEL類型代替static char的key return objc_getAssociatedObject(self, @selector(str1)); } @end
使用注意
當(dāng)在category中定義了與class同名的成員時(shí),會(huì)category中的成員會(huì)覆蓋class中的成員,這是因?yàn)間etter方法會(huì)優(yōu)先尋找category中的屬性。