深入category的高級使用及解惑

category的高級使用

1. 分類為什么會覆蓋掉類的同名方法眨层,對應的類方法是不存在了么?
2. 怎么解除分類對類方法的覆蓋上荡?
3.category怎么關聯(lián)對象的趴樱?
4.多個category,哪個方法優(yōu)先執(zhí)行酪捡?

Category是在Objective-C 2.0時提供的新的語言特性伊佃,其原因簡單,不管類設計的多么完美沛善,總有無法預測的狀況航揉,Category就是作為一種方式來擴展類的。

關于基礎部分金刁,網(wǎng)上很多相關文檔可供查閱帅涂,此文不贅述。
作者只做分類的底層及高級用法作使用說明尤蛮。

1. 分類為什么會覆蓋掉類的同名方法媳友,對應的類方法是不存在了么?

1. category的方法沒有“完全替換掉”原來類已經(jīng)有的方法产捞,也就是說如果category和原來類都有methodA醇锚,那么category附加完成之后,類的方法列表里會有兩個methodA
2. category的方法被放到了新方法列表的前面坯临,而原來類的方法被放到了新方法列表的后面焊唬,這也就是我們平常所說的category的方法會“覆蓋”掉原來類的同名方法,這是因為運行時在查找方法的時候是順著方法列表的順序查找的看靠,它只要一找到對應名字的方法赶促,就會罷休^_^,殊不知后面可能還有一樣名字的方法挟炬。

2. 怎么解除分類對類方法的覆蓋鸥滨?

/*
怎么調用到原來類中被category覆蓋掉的方法嗦哆?
對于這個問題,我們已經(jīng)知道category其實并不是完全替換掉原來類的同名方法婿滓,只是category在方法列表的前面而已老速,所以我們只要順著方法列表找到最后一個對應名字的方法,就可以調用原來類的方法:
*/
+ (void)useClassMethodInsteadCayegoryMethod: (SEL)seletor {
    
    if (self) {
        unsigned int methodCount;
        Method *methodList = class_copyMethodList([self class], &methodCount);
        IMP lastImp = NULL;
        SEL lastSel = NULL;
        for (NSInteger i = 0; i < methodCount; i++) {
            Method method = methodList[i];
            NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method))
                                                      encoding:NSUTF8StringEncoding];
            NSString *selectorName = NSStringFromSelector(seletor);
            if ([selectorName isEqualToString:methodName]) {
                lastImp = method_getImplementation(method);
                lastSel = method_getName(method);
            }
        }
        typedef void (*fn)(id,SEL);
        
        if (lastImp != NULL) {
            fn f = (fn)lastImp;
            f(self,lastSel);
        }
        free(methodList);
    }
}

3.category怎么關聯(lián)對象的凸主?

#import <Foundation/Foundation.h>
#import "LearnCategoryClass.h"

@interface LearnCategoryClass (Addition)

@property(nonatomic, strong) NSString *newName;



#import "LearnCategoryClass+Addition.h"
#import <objc/runtime.h>

@implementation LearnCategoryClass (Addition)

- (void)testCategory {
    NSLog(@"分類里是%@,方法名是%s",[self class], __PRETTY_FUNCTION__);
}

//運行時動態(tài)添加set和get方法(Xcode9 更新了提醒功能烁峭,超級牛逼。比如此處在分類里聲明了屬性秕铛,但不添加set/get方法會warnning约郁,這里說下,厲害了我的蘋果)
- (void)setNewName:(NSString *)newName
{
    objc_setAssociatedObject(self,
                             "newName",
                             newName,
                             OBJC_ASSOCIATION_COPY);
}

- (NSString*)newName
{
    NSString *nameObject = objc_getAssociatedObject(self, "newName");
    return nameObject;
}
@end

4.多個category但两,哪個方法優(yōu)先執(zhí)行鬓梅?

好吧,這其實不是一個問題谨湘,是一串問題绽快。
可以分為:

  1. category里的方法是什么時候注冊到Class的method_list的,在+load階段么紧阔?
  1. 如果有多個category坊罢,怎么辦?

我們知道擅耽,在類class和category中都可以有+load方法活孩,那么有兩個問題:

  1. 在class的+load方法調用的時候,我們可以調用category中聲明的方法么乖仇?
  1. 這么多個+load方法憾儒,調用順序是咋樣的呢?

答案是

  1. 可以調用乃沙,而且附加category到類的工作會先于+load方法的執(zhí)行起趾;
  2. +load的執(zhí)行順序是先class,后category警儒,而category的+load執(zhí)行順序是根據(jù)編譯順序決定的训裆。

可以這么理解方法的調用。
有一個類似有壓棧入棧的棧結構蜀铲,先把class里的methodA添加到methodList中边琉,然后添加分類中的方法,編譯器會從上到下找分類蝙茶,先找到的分類就先放入methodList中艺骂,后找到的就后放入。
所以最終形成了一個Class里的方法在最底層隆夯,最后編譯的分類在最上層的棧結構钳恕。
而方法的調用是從上到下執(zhí)行的,冉調用對應的方法蹄衷,就會從methodList里找對應的SEL忧额,找到就停止,所以Class和前面便輕易的分類雖然都在methodList里愧口,但因為找到了就不會繼續(xù)查找睦番。
以上就是方法掉用順序的原理。
當然耍属,編譯順序可以在 Build Phases里的Compile Source里修改托嚣。

奇葩問答:

  • 如果在分類里聲明了,但不實現(xiàn)厚骗,method_list里不會有,當然也不會調用分類方法示启。但若是實現(xiàn)了,即使不在.h文件聲明领舰,也會調用分類的方法夫嗓;
  • 如果分類里是- (void)testCategory,而Class里是- (int)testCategory;返回值不同冲秽,也會覆蓋舍咖,因為雖然返回值不同,但OC里锉桑,這兩者依然是一個方法排霉。
  • 對于多個分類,方法的調用是執(zhí)行最后編譯的分類方法民轴;

文末

關于category及其OC的深入研究郑诺,請轉移到Github—>OCDeepLearning
歡迎star和issues參與討論。

之于category的更底層實現(xiàn)杉武,可以參照:參考文章

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辙诞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子轻抱,更是在濱河造成了極大的恐慌飞涂,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祈搜,死亡現(xiàn)場離奇詭異较店,居然都是意外死亡,警方通過查閱死者的電腦和手機容燕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門梁呈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蘸秘,你說我怎么就攤上這事官卡』茸拢” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵寻咒,是天一觀的道長哮翘。 經(jīng)常有香客問我,道長毛秘,這世上最難降的妖魔是什么饭寺? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮叫挟,結果婚禮上艰匙,老公的妹妹穿的比我還像新娘。我一直安慰自己抹恳,他們只是感情好员凝,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著适秩,像睡著了一般绊序。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上秽荞,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天骤公,我揣著相機與錄音,去河邊找鬼扬跋。 笑死阶捆,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的钦听。 我是一名探鬼主播洒试,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼朴上!你這毒婦竟也來了垒棋?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤痪宰,失蹤者是張志新(化名)和其女友劉穎叼架,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衣撬,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡乖订,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了具练。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乍构。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖扛点,靈堂內(nèi)的尸體忽然破棺而出哥遮,到底是詐尸還是另有隱情岂丘,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布昔善,位于F島的核電站元潘,受9級特大地震影響畔乙,放射性物質發(fā)生泄漏君仆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一牲距、第九天 我趴在偏房一處隱蔽的房頂上張望返咱。 院中可真熱鬧,春花似錦牍鞠、人聲如沸咖摹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽萤晴。三九已至,卻和暖如春胁后,著一層夾襖步出監(jiān)牢的瞬間店读,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工攀芯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留屯断,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓侣诺,卻偏偏與公主長得像殖演,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子年鸳,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

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

  • 轉至元數(shù)據(jù)結尾創(chuàng)建: 董瀟偉趴久,最新修改于: 十二月 23, 2016 轉至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,682評論 0 9
  • 本文載自: http://blog.csdn.net/a316212802/article/details/49...
    MrLuckyluke閱讀 2,465評論 1 7
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)搔确,斷路器彼棍,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法妥箕,內(nèi)部類的語法滥酥,繼承相關的語法,異常的語法畦幢,線程的語...
    子非魚_t_閱讀 31,587評論 18 399
  • 藝術品收藏坎吻,名師字畫。我們常說最基本的價值是其本身所具有的文化內(nèi)涵宇葱,其中有藝術價值瘦真、歷史價值和審美價值刊头,并由其所體...
    后來呢_1911閱讀 136評論 0 0