iOS類的方法調(diào)用順序面試題

類的方法和分類的方法重名,執(zhí)行的是哪一個(gè)方法宛蚓?

首先如果重名方法不是Load方法篮灼,那么先執(zhí)行分類方法

那么如果重名方法是Load方法,那么先執(zhí)行主類再執(zhí)行分類方法路操。

下面來解釋一下疾渴,為什么重名方法是Load方法時(shí),它先執(zhí)行的是主類再執(zhí)行分類屯仗;

首先我們需要了解搞坝,類中方法的加載在objc源碼中的load_images方法中;來看看源碼實(shí)現(xiàn):!

iShot2020-10-24 13.59.26.png

看上圖方框中的代碼魁袜,就是發(fā)現(xiàn)方法桩撮,而call_load_methods就是調(diào)用方法;
下面去看看prepare_load_methods方法實(shí)現(xiàn):

iShot2020-10-24 14.00.44.png

在看到源碼實(shí)現(xiàn)后峰弹,可以清楚的看到_getObjc2NonlazyClassList非懶加載類的加載店量。然后去看看類加載的實(shí)現(xiàn)在方框中的schedule_class_load方法(后面的方法是加載分類的非懶加載方法,其代碼與下面主類方法的加載類似):

iShot2020-10-24 14.06.58.png

在這個(gè)方法中鞠呈,使用了遞歸調(diào)用融师,知道cls不存在,就找完了蚁吝。接下來就是add_class_to_loadable_list方法:

iShot2020-10-24 14.08.05.png

此方法的作用就是將所有非懶加載類的方法添加到loadable_classes這張表中旱爆;

至于方法的發(fā)現(xiàn)就已經(jīng)清楚了,首先發(fā)現(xiàn)主類方法添加到表中窘茁,在add_class_to_loadable_list中有源碼實(shí)現(xiàn)怀伦,然后加載分類方法,同樣添加到表中山林,在add_category_to_loadable_list方法有實(shí)現(xiàn)房待。

接下來就是對(duì)類中方法的加載了,同樣的回答load_images方法中的call_load_methods方法:

iShot2020-10-24 14.15.19.png

看到這個(gè)方法驼抹,其實(shí)很簡單桑孩,首先對(duì)主類的加載調(diào)用,然后對(duì)分類方法的加載調(diào)用砂蔽,最后釋放內(nèi)存空間洼怔。
那么方法的加載就已經(jīng)很清晰了,首先調(diào)用call_class_loads加載主類的方法左驾,然后調(diào)用call_category_loads加載分類的方法,而所有方法的加載都在load_images方法中。

這道面試題其實(shí)是有關(guān)方法的調(diào)用順序的诡右,下面做一個(gè)總結(jié):

普通方法:包括initialize安岂,因?yàn)榉诸惙椒ㄊ窃陬恟ealize之后attach進(jìn)去的,插在前面,所以優(yōu)先調(diào)用分類的方法

注意 : 不是分類覆蓋主類哦!!!!

Load方法:

1: 主類load
2: 分類load (分類之間 看編譯的順序)

方法的本質(zhì)帆吻,sel是什么?IMP是什么?兩者之間的關(guān)系又是什么域那?

SEL : 方法編號(hào)
IMP : 函數(shù)指針地址

方法的本質(zhì):發(fā)送消息, 消息會(huì)有以下幾個(gè)流程

1:快速查找 (objc_msgSend)~ cache_t 緩存消息
2:慢速查找~ 遞歸自己| 父類 ~ lookUpImpOrForward
3:查找不到消息: 動(dòng)態(tài)方法解析 ~ resolveInstanceMethod
4:消息快速轉(zhuǎn)發(fā)~ forwardingTargetForSelector
5:消息慢速轉(zhuǎn)發(fā)~ methodSignatureForSelector & forwardInvocation

sel 是方法編號(hào) ~ 在read_images 期間就編譯進(jìn)入了內(nèi)存
imp 就是我們函數(shù)實(shí)現(xiàn)指針 ,找imp 就是找函數(shù)的過程
sel 就相當(dāng)于書本的目錄 tittle
imp 就是書本的?碼 查找具體的函數(shù)就是想看這本書里面具體篇章的內(nèi)容
1:我們首先知道想看什么 ~ tittle (sel)
2:根據(jù)目錄對(duì)應(yīng)的?碼 (imp)
3:翻到具體的內(nèi)容

能否向編譯后的得到的類中增加實(shí)例變量?能否想運(yùn)行時(shí)創(chuàng)建的類中添加實(shí)例變量

答案:
1:不能向編譯后的得到的類中增加實(shí)例變量
2:只要內(nèi)沒有注冊(cè)到內(nèi)存還是可以添加

原因:我們編譯好的實(shí)例變量存儲(chǔ)的位置在 ro猜煮,一旦編譯完成次员,內(nèi)存結(jié)構(gòu)就完全確定 就無法修改
可以添加屬性 + 方法

[self class]和[super class]的區(qū)別以及原理分析

下面看一段代碼:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Teacher *teacher = [[Teacher alloc] init];;
        NSLog(@"%@",teacher);
    }
    return 0;
}

@implementation Teacher
- (instancetype)init{
    self = [super init];
    if (self) {
        NSLog(@"%@ - %@",[self class],[super class]);
    }
    return self;
}

當(dāng)執(zhí)行程序,打印的結(jié)果都會(huì)是Teacher王带。

那么為什么會(huì)是這樣一個(gè)結(jié)果呢淑蔚?

首先[self class]我們是可以理解的,他的底層實(shí)現(xiàn)是返回object_getClass(self)愕撰,而object_getClass方法獲取的是該類的Isa刹衫,那就很好理解了,所以打印的是Teacher搞挣。

[super class]就比較難理解了带迟,首先super是一個(gè)關(guān)鍵字,而self其實(shí)是init方法的隱藏參數(shù)囱桨。那么現(xiàn)在就需要去了解super是什么東西仓犬;

通過clang轉(zhuǎn)換cpp文件,找到init方法實(shí)現(xiàn):

static instancetype _I_Teacher_init(Teacher * self, SEL _cmd) {
    self = ((Teacher *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Teacher"))}, sel_registerName("init"));
    if (self) {
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_hr_l_56yp8j4y11491njzqx6f880000gn_T_Teacher_d9115f_mi_0,((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")),
              
              
              objc_msgSendSuper(
        {(id)self, (id)class_getSuperclass(objc_getClass("Teacher"))},
                                sel_registerName("class")));
    }
    return self;
}

可以看到super關(guān)鍵字轉(zhuǎn)換的是class_getSuperclass舍肠;
下圖是objc_super的結(jié)構(gòu)搀继,他的第一個(gè)參數(shù)就是receiver,也就是一個(gè)消息接收者貌夕,而看cpp文件中init實(shí)現(xiàn)后律歼,super的第一個(gè)參數(shù)就是self,那也就可以解釋的通了啡专,為什么打印的是Teacher了险毁。

iShot2020-10-24 14.38.13.png

結(jié)果是對(duì)的,但是過程不一定就對(duì)了们童;

首先我們需要明白畔况,用selfsuper的區(qū)別在哪,那就是super少走了一層方法慧库,這個(gè)在類和isa的走位圖中有詳細(xì)解釋跷跪,首先super的調(diào)用,讓系統(tǒng)節(jié)約了在Teacher這一層找方法齐板,而是直接從父類開始找方法吵瞻。

super的底層實(shí)現(xiàn)并不是class_getSuperclass而是objc_msgSendSuper2葛菇,那是如何知道的呢?

init方法的if判斷處打上斷點(diǎn)橡羞,通過查看匯編的形式去看:

iShot2020-10-24 14.51.58.png

可以看到它在之前調(diào)用了objc_msgSendSuper2方法眯停,而不是走class_getSuperclass,這就是運(yùn)行時(shí)的處理卿泽。而objc_msgSendSuper2的底層實(shí)現(xiàn)是用匯編寫的莺债,就不詳細(xì)介紹了。

面試題签夭,內(nèi)存平移

首先看一段代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    Class cls = [Person class];
    void  *kc = &cls;  // 
    Person *person = [Person alloc];
    [(__bridge id)kc saySomething];
    
    [person saySomething]; 

  
}
- (void)saySomething{ 
    NSLog(@"%s",__func__);
}

看上面的代碼:kc是指向cls的內(nèi)存地址齐邦,當(dāng)使用clskc執(zhí)行saySomething方法,打印的結(jié)果都是一樣的第租;

那么現(xiàn)在修改部分代碼:

NSLog(@"%s - %@",__func__,self.name);

其中namePerson類的一個(gè)NSString類型的屬性措拇,并沒有對(duì)name賦值;

那么執(zhí)行代碼后煌妈,結(jié)果卻不一樣了:


iShot2020-10-24 15.20.36.png

可以看到使用person調(diào)用方法的結(jié)果為null儡羔,這是什么愿意導(dǎo)致的?

下面打印一下類的地址信息:

Class cls = [Person class];
    void  *kc = &cls;  // 
    Person *person = [Person alloc];
NSLog(@"%p - %p",&person,kc);
void *sp  = (void *)&self;
    void *end = (void *)&person;
    long count = (sp - end) / 0x8;

    for (long i = 0; i<count; i++) {
        void *address = sp - 0x8 * i;
        if ( i == 1) {
            NSLog(@"%p : %s",address, *(char **)address);
        }else{
            NSLog(@"%p : %@",address, *(void **)address);
        }
    }
iShot2020-10-24 15.29.10.png

上圖打印的信息依次為:
self cmd (id)class_getSuperclass(objc_getClass("Person")) self cls kc person

這些信息都是改控制器中的內(nèi)存地址信息璧诵,類似于棧的結(jié)構(gòu)一樣汰蜘,先進(jìn)后出。

而在kcperson調(diào)用方法時(shí)之宿,首先由kc調(diào)用族操,打印的是棧頂?shù)牡谝粋€(gè)元素0x7ffeece44058 : <ViewController: 0x7fe5b5c0af70>,而當(dāng)person調(diào)用方法時(shí)比被,它會(huì)先經(jīng)過平移內(nèi)存色难,去找到name,平移8字節(jié)等缀,得到的是0x7ffeece44050 : viewDidLoad枷莉,而取的值與屬性類型不匹配,因此打印的結(jié)果為null尺迂,那么就很好理解了笤妙。

如果將name類型改為int型,再執(zhí)行程序會(huì)出現(xiàn)問題噪裕,因?yàn)?code>int是4字節(jié)蹲盘,無法識(shí)別讀取的內(nèi)容。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末膳音,一起剝皮案震驚了整個(gè)濱河市召衔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祭陷,老刑警劉巖苍凛,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趣席,死亡現(xiàn)場離奇詭異,居然都是意外死亡毫深,警方通過查閱死者的電腦和手機(jī)吩坝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門毒姨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哑蔫,“玉大人,你說我怎么就攤上這事弧呐≌⒚裕” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵俘枫,是天一觀的道長腥沽。 經(jīng)常有香客問我,道長鸠蚪,這世上最難降的妖魔是什么今阳? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮茅信,結(jié)果婚禮上盾舌,老公的妹妹穿的比我還像新娘。我一直安慰自己蘸鲸,他們只是感情好妖谴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著酌摇,像睡著了一般膝舅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窑多,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天仍稀,我揣著相機(jī)與錄音,去河邊找鬼埂息。 笑死技潘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的耿芹。 我是一名探鬼主播崭篡,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吧秕!你這毒婦竟也來了琉闪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤砸彬,失蹤者是張志新(化名)和其女友劉穎颠毙,沒想到半個(gè)月后斯入,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛀蜜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年刻两,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滴某。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡磅摹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出霎奢,到底是詐尸還是另有隱情户誓,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布幕侠,位于F島的核電站帝美,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏晤硕。R本人自食惡果不足惜悼潭,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望舞箍。 院中可真熱鬧舰褪,春花似錦、人聲如沸创译。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽软族。三九已至刷喜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間立砸,已是汗流浹背掖疮。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颗祝,地道東北人浊闪。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像螺戳,于是被迫代替她去往敵國和親搁宾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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