iOS之Category(Category的調(diào)用)

Category擴(kuò)展唧领,它是對(duì)一個(gè)類進(jìn)行功能的擴(kuò)展处嫌。
在項(xiàng)目的開發(fā)過(guò)程中绒尊,在不斷的迭代開發(fā)過(guò)程中够傍,我們的類也不可避免的要根據(jù)需求來(lái)增加新的功能甫菠,而這個(gè)時(shí)候很多的人可能會(huì)新建一個(gè)子類,然后在子類中去增加我們的新功能冕屯,這確實(shí)能夠?qū)崿F(xiàn)我們的目的寂诱,但是久而久之,我們會(huì)因?yàn)樾陆ǖ念愒絹?lái)越多安聘,導(dǎo)致項(xiàng)目也越來(lái)越龐大痰洒,而且也很難管理,這個(gè)時(shí)候Category就派上用場(chǎng)了浴韭,我們可以將一組具有相似的功能的擴(kuò)展放在一個(gè)Category里面丘喻,這樣就可以進(jìn)行模塊化劃分功能。

Category的調(diào)用

首先我們來(lái)了解一下類擴(kuò)展念颈,涉及到多個(gè)擴(kuò)展重寫類的同一個(gè)方法的調(diào)用順序

1泉粉、一個(gè)類的擴(kuò)展的情況

首先創(chuàng)建一個(gè)Person類,里面有一個(gè)addPerson:方法榴芳,然后建立一個(gè)Person類的擴(kuò)展Person+Extend嗡靡,里面可以擴(kuò)展你的其他方法,在這里我們實(shí)驗(yàn)一下繼續(xù)擴(kuò)展addPerson:方法窟感,看看調(diào)用的順序枕荞。

Person類

@implementation Person

- (void)addPerson:(NSString *)a {

    NSLog(@"Person類里面~~~~~~%@", self);
}

@end

擴(kuò)展Extend里面

@implementation Person (Extend)

- (void)addPerson:(NSString *)a {

    NSLog(@"Extend~~~~~~%@", self);
}

@end

調(diào)用

 - (void)test3 {

    Person *person = [[Person alloc] init];
    
    [person addPerson:@"a"];
    
}

發(fā)現(xiàn)只打印了擴(kuò)展的輸出:

2017-03-24 22:37:49.135 RunTimeDemo[84566:15956638] Extend~~~~~~<Person: 0x608000004cd0>

并沒(méi)有打印Person原來(lái)方法的addPerson:方法粟害,所以擴(kuò)展有更高的優(yōu)先級(jí)千元,如果擴(kuò)展里出現(xiàn)了和原類里面相同的方法暖眼,那么會(huì)直接調(diào)用擴(kuò)展里的方法哩至,而不會(huì)調(diào)用類里面原來(lái)的方法。這里擴(kuò)展的方法不是覆蓋了類里面的方法蜜自,類里面的方法和擴(kuò)展里的方法都存在類的結(jié)構(gòu)空間菩貌,但是最先尋找到的是擴(kuò)展里的方法,所以先調(diào)用該方法的實(shí)現(xiàn)袁辈。更具體的原因會(huì)在之后用runtime進(jìn)行解釋菜谣。

2、兩個(gè)類擴(kuò)展的情況

在上文的基礎(chǔ)上晚缩,我們?cè)趧?chuàng)建一個(gè)Person的擴(kuò)展Person+A,然后同樣實(shí)現(xiàn)了addPerson:的方法媳危,然后在調(diào)用這個(gè)方法荞彼,看一下編譯器會(huì)調(diào)用哪個(gè)方法,還是兩個(gè)方法都會(huì)調(diào)用待笑。

@implementation Person (A)

- (void)addPerson:(NSString *)a {
    
    NSLog(@"A~~~~~~%@", self);
}

@end

調(diào)用

- (void)test3 {
    
    Person *person = [[Person alloc] init];
    
    [person addPerson:@"a"];
    
}

發(fā)現(xiàn)文件打印的是:

2017-03-24 22:45:39.342 RunTimeDemo[84658:16064399] A~~~~~~<Person: 0x600000009be0>

那么原來(lái)Extend擴(kuò)展里的addPerson:方法呢鸣皂,為什么沒(méi)有調(diào)用呢?
上面的編譯的順序是

調(diào)用順序

首先我們修改一下編譯的順序暮蹂,將Person+A和Person+Extend的編譯順序換一下

調(diào)用順序

我們看到打印出來(lái)的結(jié)果又變成了

2017-03-24 22:51:58.767 RunTimeDemo[84770:16152019] Extend~~~~~~<Person: 0x6000000187d0>

這個(gè)實(shí)驗(yàn)說(shuō)明當(dāng)有兩個(gè)擴(kuò)展里面有同一個(gè)方法時(shí)寞缝,會(huì)調(diào)用后編譯的那個(gè)擴(kuò)展里的方法,為什么會(huì)這樣呢仰泻,原因是當(dāng)類有擴(kuò)展方法的時(shí)候荆陆,擴(kuò)展方法的鏈表就放在原來(lái)類的方法鏈表的前面,那么在尋找方法的時(shí)候集侯,會(huì)從前面開始尋找方法被啼,當(dāng)尋找到第一個(gè)這個(gè)方法的時(shí)候,返回方法的實(shí)現(xiàn)調(diào)用棠枉,所以根據(jù)上面兩個(gè)編譯順序浓体,我用下面的圖來(lái)解釋一下:

擴(kuò)展方法結(jié)構(gòu)圖

所以當(dāng)類有多個(gè)擴(kuò)展的時(shí)候,擴(kuò)展里有相同的方法的時(shí)候辈讶,會(huì)調(diào)用最后面編譯的那個(gè)擴(kuò)展里的方法命浴。

3、在類擴(kuò)展里進(jìn)行方法交換

現(xiàn)在暫時(shí)的屏蔽掉Person+Extend的方法贱除,而新加一個(gè)Person+B擴(kuò)展生闲,現(xiàn)在對(duì)Person+A和Person+B進(jìn)行方法交換。

Person+A

@implementation Person (A)

+ (void)load
{
    Method originalMethod = class_getInstanceMethod(self, @selector(addPerson:));
    Method swizzledMethod = class_getInstanceMethod(self, @selector(a_addPerson:));
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

- (void)a_addPerson:(NSString *)a {
        
    NSLog(@"A類里面~~~~~~%@", self);

    [self a_addPerson:a];
    
}

@end

Person+B

@implementation Person (B)

+ (void)load
{
    Method originalMethod = class_getInstanceMethod(self, @selector(addPerson:));
    Method swizzledMethod = class_getInstanceMethod(self, @selector(b_addPerson:));
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

- (void)b_addPerson:(NSString *)a {
    
    NSLog(@"B類里面~~~~~~%@", self);
    
    [self b_addPerson:a];
    
}

@end

調(diào)用

- (void)test3 {
    
    Person *person = [[Person alloc] init];
    
    [person addPerson:@"a"];
    
}

打印出來(lái)的結(jié)果


結(jié)果

發(fā)現(xiàn)A擴(kuò)展和B擴(kuò)展的方法都調(diào)用了勘伺,這里擴(kuò)展的不是addPerson:方法跪腹,其實(shí)是+load方法,+load方法是一個(gè)類所在的文件引用就會(huì)調(diào)用飞醉,而+load方法是所有的擴(kuò)展文件都會(huì)調(diào)用的冲茸,所以在這里看看編譯的順序

編譯順序

所以這里看當(dāng)Person+B擴(kuò)展里的+load方法被調(diào)用的時(shí)候屯阀,將Person類里面本來(lái)的方法的實(shí)現(xiàn)和B擴(kuò)展里的方法的實(shí)現(xiàn)進(jìn)行了交換,然后編譯到Person+A方法的時(shí)候轴术,將Person的方法和A的方法交換难衰,此時(shí)Person里面方法的實(shí)現(xiàn)是B,所以就相當(dāng)于將B的實(shí)現(xiàn)和A的實(shí)現(xiàn)進(jìn)行了交換逗栽,所以就有了最后的一個(gè)圖盖袭,所以三個(gè)方法都交換了方法的實(shí)現(xiàn),當(dāng)調(diào)用Person的方法的時(shí)候彼宠,實(shí)際上是調(diào)用A的方法鳄虱,然后調(diào)用A方法的時(shí)候調(diào)用的是B方法,最后再是真正意義上的Person的方法凭峡。

交換方法

當(dāng)改變編譯的順序的時(shí)候拙已,可以看到打印順序也換了


改變編譯順序

打印出結(jié)果


結(jié)果

4、對(duì)類擴(kuò)展進(jìn)行方法交換和單獨(dú)的類擴(kuò)展

現(xiàn)在將Person+Extend文件打開摧冀,同時(shí)Person+A和Person+B進(jìn)行方法交換

打印出來(lái)的結(jié)果


結(jié)果

此時(shí)沒(méi)有打印Person里面的方法倍踪,說(shuō)明方法交換的時(shí)候交換的是Extend擴(kuò)展里的方法。

5索昂、對(duì)類擴(kuò)展添加一個(gè)屬性的時(shí)候

在 Person+Extend.h 的擴(kuò)展里加一個(gè)屬性建车,然而 Person+Extend.m里并沒(méi)有實(shí)現(xiàn)setter和getter方法

Person+Extend

@interface Person (Extend)

@property (nonatomic, copy) NSString *name;

@end

調(diào)用

- (void)test3 {
    
    Person *person = [[Person alloc] init];
    
    person.name = @"ffff";
    
}

會(huì)直接報(bào)錯(cuò)

錯(cuò)誤

當(dāng)我們?cè)赑erson的init方法里打印self.name的時(shí)候,會(huì)發(fā)現(xiàn)并沒(méi)有這個(gè)name屬性

init

說(shuō)明在類的擴(kuò)展中添加屬性的時(shí)候椒惨,編譯器并沒(méi)有自動(dòng)為我們添加setter和getter的方法缤至,而擴(kuò)展里添加屬性也并不是添加了成員變量,而我們?cè)L問(wèn)這個(gè)屬性的時(shí)候框产,其實(shí)是訪問(wèn)setter和getter方法凄杯。

測(cè)試代碼
https://github.com/xlym33/CategoryDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秉宿,隨后出現(xiàn)的幾起案子戒突,更是在濱河造成了極大的恐慌,老刑警劉巖描睦,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膊存,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡忱叭,警方通過(guò)查閱死者的電腦和手機(jī)隔崎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)韵丑,“玉大人爵卒,你說(shuō)我怎么就攤上這事∧斐梗” “怎么了钓株?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵实牡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我轴合,道長(zhǎng)创坞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任受葛,我火速辦了婚禮题涨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘总滩。我一直安慰自己纲堵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布咳秉。 她就那樣靜靜地躺著婉支,像睡著了一般。 火紅的嫁衣襯著肌膚如雪澜建。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天蝌以,我揣著相機(jī)與錄音炕舵,去河邊找鬼。 笑死跟畅,一個(gè)胖子當(dāng)著我的面吹牛咽筋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播徊件,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼奸攻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了虱痕?” 一聲冷哼從身側(cè)響起睹耐,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎部翘,沒(méi)想到半個(gè)月后硝训,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡新思,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年窖梁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夹囚。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纵刘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荸哟,到底是詐尸還是另有隱情假哎,我是刑警寧澤瞬捕,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站位谋,受9級(jí)特大地震影響山析,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掏父,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一笋轨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赊淑,春花似錦爵政、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至饱岸,卻和暖如春掺出,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苫费。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工汤锨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人百框。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓闲礼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親铐维。 傳聞我的和親對(duì)象是個(gè)殘疾皇子柬泽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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