iOS開發(fā)中利用runtime為某個(gè)類的category增加屬性
這篇文章中給出了為分類“添加成員變量”的代碼耳奕,實(shí)際用到的就是關(guān)聯(lián)對象,方法是runtime中的API闸婴,至于“添加成員變量”為什么是帶引號(hào)的芍躏,下面我們進(jìn)行解釋。
看代碼:
@interface Person (property)
@property (nonatomic, copy) NSString * name;
@end
現(xiàn)在有一個(gè)Person類以及它的一個(gè)分類庇楞,在分類中我們增加一個(gè)name屬性否纬。
我們知道如果name這個(gè)屬性直接添加在Person類中,name會(huì)自動(dòng)為Person類添加一個(gè)_name成員變量和其對應(yīng)的set睛驳、get方法的聲明和實(shí)現(xiàn)膜廊,但在分類中 @property (nonatomic, copy) NSString * name;這行代碼實(shí)際上
只生成了set、get方法的聲明蹬跃,既沒有set钥勋、get方法的實(shí)現(xiàn)也沒有成員變量_name的添加。分類中是不能直接添加成員變量的。(不能添加屬性的原因)
為了在分類中達(dá)到添加成員的目的驻啤,我們需要自己去實(shí)現(xiàn)set、get方法赊瞬,看代碼:
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self, _cmd);
}
set方法中我們是使用了runtime中的API設(shè)置關(guān)聯(lián)對象,get方法中我們是使用了runtime中的API獲取關(guān)聯(lián)對象薯蝎。
解釋“添加成員變量”帶引號(hào)
使用關(guān)聯(lián)對象這種方式雖然在外部看似乎就是添加了成員變量谤绳,但關(guān)聯(lián)對象并沒有被添加到被關(guān)聯(lián)的對象中即在Person類對象中的成員變量中并沒有name這個(gè)成員變量。
關(guān)聯(lián)對象存儲(chǔ)在哪里呢消略?
看圖瞎抛,關(guān)聯(lián)對象存儲(chǔ)在全局統(tǒng)一的一個(gè)AssociationManager中。
設(shè)置關(guān)聯(lián)對象方法中的object參數(shù)做為鍵對應(yīng)一個(gè)map胎撤,在map中key參數(shù)做為鍵對應(yīng)一個(gè)ObjectAssociation断凶,在ObjectAssociation中存放著value參數(shù)和policy參數(shù)。
0.關(guān)聯(lián)對象的本質(zhì).png
OBJC_ASSOCIATION_COPY_NONATOMIC參數(shù)
解釋一下設(shè)置關(guān)聯(lián)對象中的OBJC_ASSOCIATION_COPY_NONATOMIC這個(gè)參數(shù)飘弧,這個(gè)參數(shù)是和添加的屬性的修飾符號(hào)相對應(yīng)的次伶』拢看圖:
分類不能直接添加屬性,蘋果為什么要這樣設(shè)計(jì)柱彻?
如果基類動(dòng)態(tài)增加成員變量會(huì)導(dǎo)致所有已創(chuàng)建出的子類實(shí)例都無法使用餐胀。
方法定義是在objc_class中管理的,不管如何增刪類方法卖擅,都不影響類實(shí)例的內(nèi)存布局。