OC-Runtime-super面試題相關(guān)

面試題
***********************??MJPerson.h ??**************************
#import <Foundation/Foundation.h>

@interface MJPerson : NSObject
@property (copy, nonatomic) NSString *name;

- (void)print;
@end

***********************??MJPerson.m ??**************************  
#import "MJPerson.h"

@implementation MJPerson

- (void)print
{
    NSLog(@"my name is %@", self->_name);
}
@end

@implementation ViewController

/*
 1.print為什么能夠調(diào)用成功挟鸠?
 
 2.為什么self.name變成了ViewController等其他內(nèi)容
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    id cls = [MJPerson class];

    void *obj = &cls;

    [(__bridge id)obj print];
    
}
@end

RUN>

*********************** ??運行結(jié)果?? **************************
2021-05-08 16:03:34.586222+0800 Interview02-super[4242:166676] my name is <ViewController: 0x7fb47340ecf0>

1.print為什么能夠調(diào)用成功没咙?

2.為什么self.name變成了ViewController等其他內(nèi)容

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString *test = @"123";
    id cls = [MJPerson class];
    void *obj = &cls;
    [(__bridge id)obj print];
}

RUN>

*********************** ??運行結(jié)果?? **************************
2021-05-08 16:05:32.180416+0800 Interview02-super[4288:170283] my name is 123
image-20210508160938861

很奇怪,怎么會這樣呢? 首先第一點是為什么會調(diào)用到MJPerson- (void)print方法,第二,局部變量 NSString *test = @"123";怎么就變成了person的實例成員芭逝。

- (void)viewDidLoad {
    [super viewDidLoad];
    //調(diào)用print
    MJPerson *person = [[MJPerson alloc]init];
    [person print];
}

RUN>

*********************** ??運行結(jié)果?? **************************
2021-05-09 19:55:04.568600+0800 Interview02-super[2315:98649] my name is (null)    
image-20210509200146018
 id cls = [MJPerson class];
 void *obj = &cls;
 [(__bridge id)obj print];

這段代碼在內(nèi)存結(jié)構(gòu)上發(fā)生了什么情況

image-20210509201257058

[(__bridge id)obj print]; 調(diào)用了能夠調(diào)用到MJPerson- (void)print方法荡灾。那我們把obj看出person的instance會是什么情況

image-20210509202016984

他們的內(nèi)存結(jié)構(gòu)何其相似.cls在這里不就等價于isa么?他們都指向 MJPerson類對象.

[person print];通過實例對象 personisa指針找到MJPerson 類對象,然后從類對象的方法列表中查找方法.所以毡惜,方法的調(diào)用本質(zhì)就是只要能找到類對象.而[(__bridge id)obj print];,指針變量obj中存儲的cls恰巧就指向類對象,當(dāng)消息系統(tǒng)objc_msgSend把obj當(dāng)成類了拓轻,在他所指向的地址,獲取前8位地址作為類的isa指針经伙,指向了MJPerson 類對象 扶叉,所以能夠當(dāng)成MJPerson類,所以最后能調(diào)用成功.

接著分析 my name is 123 這個局部變量 NSString *test = @"123";怎么就變成了person的實例成員帕膜。

// 局部變量分配在椩嫜酰空間
// 棧空間分配垮刹,從高地址到低地址
void test()
{
    long long a = 4; // 0x7ffee638bff8
    long long b = 5; // 0x7ffee638bff0
    long long c = 6; // 0x7ffee638bfe8
    long long d = 7; // 0x7ffee638bfe0
    
    NSLog(@"%p %p %p %p", &a, &b, &c, &d);
}

int main(int argc, char * argv[]) {
    @autoreleasepool {
        test();
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

RUN>

*********************** ??運行結(jié)果?? **************************
2021-05-09 20:30:17.556720+0800 Interview02-super[2557:120622] 0x7ffeed6a7c28 0x7ffeed6a7c20 0x7ffeed6a7c18 0x7ffeed6a7c10

從打印結(jié)果中可以看到,棧內(nèi)存分配空間是從高地址往低地址分配的,<font color='red'>先創(chuàng)建的局部變量分配在高地址,后創(chuàng)建的分配在低地址</font>.

NSString *test = @"123";
id cls = [MJPerson class];
void *obj = &cls;
[(__bridge id)obj print];

繼續(xù)查看這段代碼的內(nèi)存結(jié)構(gòu)

image-20210509203828027

上面我們已經(jīng)分析過达吞,把cla看出isa指針,isa指針后面8個地址就是_name 屬性指向地址危纫。在獲取self.name的時候,如果轉(zhuǎn)換成匯編代碼會發(fā)現(xiàn)本質(zhì)上就是找到isa指針,然后越過8個字節(jié),從而找到_name.這就是內(nèi)存訪問的本質(zhì):找到某塊內(nèi)存的地址,讀取地址中的值.

[(__bridge id)obj print]; 也會同樣的越過cls這8個字節(jié)找到test.所以最后就打印的是my name is 123;

super 關(guān)鍵字的一點補充

在前面講super關(guān)鍵字的時候,我們看到super轉(zhuǎn)換為c++代碼的時候,被轉(zhuǎn)換成了objc_msgSendSuper(arg1,arg2)函數(shù).其實實際上底層執(zhí)行并不是objc_msgSendSuper(arg1,arg2)函數(shù),而是objc_msgSendSuper2(arg1,arg2)函數(shù).我們在[super viewDidLoad];處打個斷點,然后顯示匯編語言看一下:

image-20210509205809559

并且上面講的objc_msgSendSuper(arg1,arg2)中的第一個參數(shù)arg1__rw_objc_super結(jié)構(gòu)體,這個結(jié)構(gòu)體如下:

struct __rw_objc_super { 
    struct objc_object *object; 
    struct objc_object *superClass; 
}

objc_super2的結(jié)構(gòu)體如下:

struct objc_super2 {
    id receiver;
    Class current_class;
};

可以看到objc_super2這個結(jié)構(gòu)體中傳入的是Class current_class;也就是當(dāng)前類.而在_objc_msgSendSuper2內(nèi)部獲取當(dāng)前類的superClass:

    ENTRY _objc_msgSendSuper2
    UNWIND _objc_msgSendSuper2, NoFrame
    MESSENGER_START

    ldp x0, x16, [x0]       // x0 = real receiver, x16 = class
    ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass
    CacheLookup NORMAL

    END_ENTRY _objc_msgSendSuper2

    
    ENTRY _objc_msgLookupSuper2
    UNWIND _objc_msgLookupSuper2, NoFrame

    ldp x0, x16, [x0]       // x0 = real receiver, x16 = class
    ldr x16, [x16, #SUPERCLASS] // x16 = class->superclass
    CacheLookup LOOKUP

    END_ENTRY _objc_msgLookupSuper2
image-20210509210422437
image-20210509211303627

所以,super底層其實是調(diào)用objc_msgSendSuper2()函數(shù),然后傳入的是當(dāng)前類對象,只不過在內(nèi)部又回取出當(dāng)前類對象的superclass.
這只是一個小細(xì)節(jié),和我們最開頭說的也不矛盾,知悉就好.

特別備注

本系列文章總結(jié)自MJ老師在騰訊課堂iOS底層原理班(下)/OC對象/關(guān)聯(lián)對象/多線程/內(nèi)存管理/性能優(yōu)化宗挥,相關(guān)圖片素材均取自課程中的課件。如有侵權(quán)种蝶,請聯(lián)系我刪除,謝謝瞒大!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末螃征,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子透敌,更是在濱河造成了極大的恐慌盯滚,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酗电,死亡現(xiàn)場離奇詭異魄藕,居然都是意外死亡,警方通過查閱死者的電腦和手機撵术,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門背率,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事寝姿〗慌牛” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵饵筑,是天一觀的道長埃篓。 經(jīng)常有香客問我,道長根资,這世上最難降的妖魔是什么架专? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮玄帕,結(jié)果婚禮上胶征,老公的妹妹穿的比我還像新娘。我一直安慰自己桨仿,他們只是感情好睛低,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著服傍,像睡著了一般钱雷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吹零,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天罩抗,我揣著相機與錄音,去河邊找鬼灿椅。 笑死套蒂,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的茫蛹。 我是一名探鬼主播操刀,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼婴洼!你這毒婦竟也來了骨坑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柬采,失蹤者是張志新(化名)和其女友劉穎欢唾,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粉捻,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡礁遣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肩刃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祟霍。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡杏头,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浅碾,到底是詐尸還是另有隱情大州,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布垂谢,位于F島的核電站厦画,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏滥朱。R本人自食惡果不足惜根暑,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望徙邻。 院中可真熱鬧排嫌,春花似錦、人聲如沸缰犁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帅容。三九已至颇象,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間并徘,已是汗流浹背遣钳。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留麦乞,地道東北人蕴茴。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像姐直,于是被迫代替她去往敵國和親倦淀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

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

  • 一. super底層實現(xiàn) 先看結(jié)論: [super message]的底層實現(xiàn)① 消息接收者仍然是子類對象② 從父...
    Imkata閱讀 340評論 0 0
  • 究一下super關(guān)鍵字,在講之前我們先看一下下面四條語句輸出打印什么 RUN>******************...
    蔣斌文閱讀 200評論 0 0
  • 參閱文章‘http://www.reibang.com/p/a3fb0919877c’ 第一章 1.簡介 Obj...
    星空夢想閱讀 883評論 0 0
  • 前言:面試筆試都是必考語法知識點简肴。請認(rèn)真復(fù)習(xí)和深入研究OC晃听。 目錄:iOS-面試題-OC基礎(chǔ)篇 (1) - (84...
    麥穗0615閱讀 4,258評論 0 33
  • 數(shù)據(jù)結(jié)構(gòu):objc_object,objc_class砰识,isa,class_data_bits_t佣渴,cache_t...
    lp_lp閱讀 3,239評論 0 12