Category深度解析

因?yàn)镃ategory在iOS平時(shí)的開(kāi)發(fā)中用的比較多大审,所以本文從各個(gè)方面介紹一下Category芥牌,很多地方都是自己的理解贿肩,歡迎各位看到的同學(xué)批評(píng)指正峦椰,多多交流。

一汰规、Category作用

  1. 為已存在的類(lèi)添加方法汤功;對(duì)類(lèi)進(jìn)行了很好的擴(kuò)展,應(yīng)對(duì)變化的需求溜哮。
  2. 可以把一個(gè)類(lèi)的實(shí)現(xiàn)分散到多個(gè)文件中滔金,使得每個(gè)文件不至于龐大,而且可以聚集同一邏輯的代碼在一個(gè)文件中茂嗓。同時(shí)餐茵,也可以按需加載方法。
  3. 同一個(gè)類(lèi)可以由多個(gè)人共同完成述吸。

二忿族、為什么category不能添加屬性或者說(shuō)是成員變量

這個(gè)問(wèn)題從runtime的角度進(jìn)行分析。
下圖是objc_class結(jié)構(gòu)體:


classOfRuntime.png

不詳細(xì)介紹每一個(gè)字段的含義了蝌矛,主要介紹與category相關(guān)的部分:
在上面的objc_class結(jié)構(gòu)體中道批,ivars是objc_ivar_list(成員變量列表)指針;methodLists是指向objc_method_list指針的指針入撒。在Runtime中暂幼,objc_class結(jié)構(gòu)體大小是固定的,不可能往這個(gè)結(jié)構(gòu)體中添加數(shù)據(jù)蘸鲸,只能修改榨婆。所以ivars指向的是一個(gè)固定區(qū)域,只能修改成員變量值氮唯,不能增加成員變量個(gè)數(shù)鉴吹。methodList是是一個(gè)二維數(shù)組,所以可以修改*methodLists的值來(lái)增加成員方法惩琉,雖沒(méi)辦法擴(kuò)展methodLists指向的內(nèi)存區(qū)域豆励,卻可以改變這個(gè)內(nèi)存區(qū)域的值(存儲(chǔ)的是指針)。因此瞒渠,可以動(dòng)態(tài)添加方法良蒸,不能添加成員變量。類(lèi)似的是protocol伍玖,因?yàn)樗蔷幾g器處理的嫩痰,所以可以添加變量。category是在運(yùn)行時(shí)處理的窍箍。

三串纺、怎么樣可以實(shí)現(xiàn)添加屬性或者說(shuō)添加成員變量

上面說(shuō)了category中不可能添加成員變量或?qū)傩岳雎谩R驗(yàn)橄到y(tǒng)無(wú)法合成實(shí)現(xiàn)屬性所需的實(shí)例變量,所以category中也無(wú)法添加@property纺棺。但有時(shí)候確實(shí)需要添加屬性榄笙,那有沒(méi)有其他辦法,可以不改變對(duì)象的內(nèi)存結(jié)構(gòu)祷蝌,變相的給對(duì)象增加成員變量茅撞。
我們可以Runtime的objc_getAssociatedObject和objc_setAssociatedObject方法來(lái)模擬屬性的get和set方法,用關(guān)聯(lián)對(duì)象來(lái)模擬實(shí)例變量巨朦,這樣就有了@property的三要素米丘,只是跟@property的實(shí)現(xiàn)機(jī)制是完全不一樣的。
有兩種方式罪郊,第一種代碼更簡(jiǎn)潔:

.h文件:

@property (nonatomic) NSString Id;

.m文件蠕蚜,要#import <objc/runtime.h>

- (NSString *)Id
{
   return objc_getAssociatedObject(self, @selector(Id));
}

- (void)setId:(NSString *)Id
{
   objc_setAssociatedObject(self, @selector(Id), Id, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

第二種:

static void *UIViewPoint =@"UIViewPoint";
@implementation UIView (Point)

@dynamic pointView;

- (void)setPointView:(UIView *)pointView {
    objc_setAssociatedObject(self, UIViewPoint, pointView,OBJC_ASSOCIATION_RETAIN);
}

- (UIView *)pointView {
   return objc_getAssociatedObject(self, UIViewPoint);
}

這兩個(gè)方法的原型如下:

id objc_getAssociatedObject(id object, const void *key);
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

@selector(Id) 是參數(shù)中的 key,方法二中使用了靜態(tài)指針 static void * 類(lèi)型的參數(shù)來(lái)代替悔橄,第一種方法因?yàn)槭÷粤寺暶鲄?shù)的代碼靶累,并且能很好地保證 key 的唯一性,所以更簡(jiǎn)潔癣疟。

OBJC_ASSOCIATION_RETAIN_NONATOMIC 從字面意思就能猜到它是和屬性的修飾符是對(duì)應(yīng)的挣柬。對(duì)應(yīng)關(guān)系見(jiàn)如下的定義:

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                        *   The association is not made atomically. */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                        *   The association is not made atomically. */
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                        *   The association is made atomically. */
    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                        *   The association is made atomically. */
};

當(dāng)屬性是基本數(shù)據(jù)類(lèi)型的時(shí)候,可能只是需要添加get和set方法睛挚,不需要實(shí)例變量的時(shí)候邪蛔,可以在category中這樣添加屬性,這種方式扎狱,同樣沒(méi)有改變對(duì)象的內(nèi)存結(jié)構(gòu)侧到。

@property (nonatomic) CGFloat left;
   @property (nonatomic) CGFloat right;

- (CGFloat)left {
    return self.frame.origin.x;
}
- (void)setLeft:(CGFloat)x {
    CGRect frame = self.frame;
    frame.origin.x = x;
    self.frame = frame;
}
- (CGFloat)right {
    return self.left + self.width;
}

- (void)setRight:(CGFloat)right {
    if(right == self.right){
        return;
    }
    CGRect frame = self.frame;
    frame.origin.x = right - frame.size.width;
    self.frame = frame;
}

我查了很多資料,很多人認(rèn)為category可以添加屬性淤击,但是不可以添加成員變量匠抗,我覺(jué)得這種說(shuō)法是不嚴(yán)謹(jǐn)?shù)模詫?xiě)了這篇博客污抬,來(lái)總結(jié)一下汞贸。如果有理解的不對(duì)的地方,希望看到的朋友指正印机,大家多多交流矢腻。

參考:

  1. http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/
  2. http://zhangbuhuai.com/2015/04/26/unstanding-the-Objective-C-Runtime-part1/
  3. http://draveness.me/ao/
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市射赛,隨后出現(xiàn)的幾起案子多柑,更是在濱河造成了極大的恐慌,老刑警劉巖楣责,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竣灌,死亡現(xiàn)場(chǎng)離奇詭異诫隅,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)帐偎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蛔屹,“玉大人削樊,你說(shuō)我怎么就攤上這事⊥枚荆” “怎么了漫贞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)育叁。 經(jīng)常有香客問(wèn)我迅脐,道長(zhǎng),這世上最難降的妖魔是什么豪嗽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任谴蔑,我火速辦了婚禮,結(jié)果婚禮上龟梦,老公的妹妹穿的比我還像新娘隐锭。我一直安慰自己,他們只是感情好计贰,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布钦睡。 她就那樣靜靜地躺著,像睡著了一般躁倒。 火紅的嫁衣襯著肌膚如雪荞怒。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,682評(píng)論 1 312
  • 那天秧秉,我揣著相機(jī)與錄音褐桌,去河邊找鬼。 笑死福贞,一個(gè)胖子當(dāng)著我的面吹牛撩嚼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挖帘,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼完丽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拇舀?” 一聲冷哼從身側(cè)響起逻族,我...
    開(kāi)封第一講書(shū)人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骄崩,沒(méi)想到半個(gè)月后聘鳞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體薄辅,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年抠璃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了站楚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡搏嗡,死狀恐怖窿春,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情采盒,我是刑警寧澤旧乞,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站磅氨,受9級(jí)特大地震影響尺栖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜烦租,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一延赌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧左权,春花似錦皮胡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至锌杀,卻和暖如春甩栈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糕再。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工量没, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人突想。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓殴蹄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親猾担。 傳聞我的和親對(duì)象是個(gè)殘疾皇子袭灯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,732評(píng)論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,569評(píng)論 33 466
  • 對(duì)于從事 iOS 開(kāi)發(fā)人員來(lái)說(shuō)绑嘹,所有的人都會(huì)答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢(mèng)夜繁星閱讀 3,726評(píng)論 7 64
  • 文|張小魚(yú) 如果不能住在你心里工腋, 都是客死他鄉(xiāng)姨丈。 ...
    張小魚(yú)716閱讀 248評(píng)論 1 2
  • 相信用過(guò)小米手機(jī)的同學(xué)都遇到一個(gè)問(wèn)題蟋恬,不管你是MIUI7還是內(nèi)測(cè)中的MIUI8翁潘,即使你是很早的MIUI5、MIUI...
    科技達(dá)人15閱讀 6,887評(píng)論 0 0