objc_msgSend(一)

一锐锣、Runtime

runtime稱之為運行時,與之相對的是編譯時
運行時著洼,是代碼跑起來樟遣,被裝載到內存中的過程,是動態(tài)階段身笤,此時出錯會導致程序崩潰
編譯時豹悬,是源代碼翻譯成機器能識別的代碼的過程,是靜態(tài)階段液荸,主要做一些詞法分析瞻佛,語法分析等操作

二、Runtime調用的三種途徑

runtime調用的三種途徑

三娇钱、objc_msgSend

一伤柄、方法的本質
isa結構分析中,我們通過Clang查看了對象的本質文搂,同樣的适刀,這里我們一樣可以使用Clang查看方法的本質

//main函數(shù)中方法的調用
LGPerson *person = [LGPerson alloc];
[person sayHello];

//clang后的方法的調用
LGPerson *person = ((LGPerson *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("LGPerson"), sel_registerName("alloc"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)person, sel_registerName("sayHello"));

可以看出,方法的本質objc_msgSend(消息發(fā)送)
這里我們驗證一下细疚,它們是不是真的一樣:
1蔗彤、導入頭文件<objc/message.h>
2川梅、設置enable strict checking of obc_msgSend callsNO(否則objc_msgSend的參數(shù)會報錯)

LGPerson *person = [LGPerson alloc];
//1.方法的調用
[person sayHello];
//2.消息發(fā)送
objc_msgSend(person, sel_registerName("sayHello"));

打印結果如圖:

方法調用與objc_msgSend打印結果

可以看到,打印結果是一樣的然遏,所以[person sayHello]等價于objc_msgSend(person, sel_registerName("sayHello"))

二贫途、方法的調用,會執(zhí)行父類的實現(xiàn)

1待侵、定義兩個類LGTeacher丢早、LGPerson

@interface LGTeacher : NSObject
- (void)sayHello;
@end

@implementation LGTeacher
- (void)sayHello {
    NSLog(@"666");
}
@end

@interface LGPerson : LGTeacher
- (void)sayHello;
- (void)sayNB;
@end

@implementation LGPerson
- (void)sayNB {
    NSLog(@"666");
}
@end

可以看到,LGPerson只聲明了sayHello方法卻沒有實現(xiàn)秧倾,但是父類LGTeacher實現(xiàn)了

2怨酝、通過objc_msgSendSuper調用父類方法

LGPerson *person = [LGPerson alloc];
LGTeacher *teacher = [LGTeacher alloc];
[person sayHello];

struct objc_super lgsuper;
lgsuper.receiver = person;//消息的接收者還是person
lgsuper.super_class = [LGTeacher class];//告訴父類是誰
////消息的接受者還是自己 - 父類 - 請你直接找我的父親
objc_msgSendSuper(&lgsuper, sel_registerName("sayHello"));

objc_msgSendSuper方法中有兩個參數(shù):

OBJC_EXPORT id _Nullable
objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
#endif

結構體 objc_supersel

struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;

    /// Specifies the particular superclass of the instance to message. 
#if !defined(__cplusplus)  &&  !__OBJC2__
    /* For compatibility with old objc-runtime.h header */
    __unsafe_unretained _Nonnull Class class;
#else
    __unsafe_unretained _Nonnull Class super_class;
#endif
    /* super_class is the first class to search */
};
#endif

結構體中需要指定receiversuper_class

3、打印結果如圖:

方法的調用那先,會執(zhí)行父類的實現(xiàn)

可以看出农猬,無論是[person sayHello]還是objc_msgSendSuper(&lgsuper, sel_registerName("sayHello"))執(zhí)行的都是父類中的實現(xiàn)

三、初探objc_msgSend

打開源碼搜索objc_msgSend售淡,選擇arm64.s后綴的文件斤葱,可以查找objc_msgSend的源碼實現(xiàn),發(fā)現(xiàn)是匯編實現(xiàn)

//---- 消息發(fā)送 -- 匯編入口--objc_msgSend主要是拿到接收者的isa信息
ENTRY _objc_msgSend 
//---- 無窗口
    UNWIND _objc_msgSend, NoFrame 
    
//---- p0 和空對比揖闸,即判斷接收者是否存在揍堕,其中p0是objc_msgSend的第一個參數(shù)-消息接收者receiver
    cmp p0, #0          // nil check and tagged pointer check 
//---- le小于 --支持taggedpointer(小對象類型)的流程
#if SUPPORT_TAGGED_POINTERS
    b.le    LNilOrTagged        //  (MSB tagged pointer looks negative) 
#else
//---- p0 等于 0 時,直接返回 空
    b.eq    LReturnZero 
#endif 
//---- p0即receiver 肯定存在的流程
//---- 根據(jù)對象拿出isa 汤纸,即從x0寄存器指向的地址 取出 isa衩茸,存入 p13寄存器
    ldr p13, [x0]       // p13 = isa 
//---- 在64位架構下通過 p16 = isa(p13) & ISA_MASK,拿出shiftcls信息贮泞,得到class信息
    GetClassFromIsa_p16 p13     // p16 = class 
LGetIsaDone:
    // calls imp or objc_msgSend_uncached 
//---- 如果有isa楞慈,走到CacheLookup 即緩存查找流程,也就是所謂的sel-imp快速查找流程
    CacheLookup NORMAL, _objc_msgSend

#if SUPPORT_TAGGED_POINTERS
LNilOrTagged:
//---- 等于空隙畜,返回空
    b.eq    LReturnZero     // nil check 

    // tagged
    adrp    x10, _objc_debug_taggedpointer_classes@PAGE
    add x10, x10, _objc_debug_taggedpointer_classes@PAGEOFF
    ubfx    x11, x0, #60, #4
    ldr x16, [x10, x11, LSL #3]
    adrp    x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGE
    add x10, x10, _OBJC_CLASS_$___NSUnrecognizedTaggedPointer@PAGEOFF
    cmp x10, x16
    b.ne    LGetIsaDone

    // ext tagged
    adrp    x10, _objc_debug_taggedpointer_ext_classes@PAGE
    add x10, x10, _objc_debug_taggedpointer_ext_classes@PAGEOFF
    ubfx    x11, x0, #52, #8
    ldr x16, [x10, x11, LSL #3]
    b   LGetIsaDone
// SUPPORT_TAGGED_POINTERS
#endif

LReturnZero:
    // x0 is already zero
    mov x1, #0
    movi    d0, #0
    movi    d1, #0
    movi    d2, #0
    movi    d3, #0
    ret

    END_ENTRY _objc_msgSend

整體執(zhí)行的流程如圖:


objc_msgSend流程圖
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末抖部,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子议惰,更是在濱河造成了極大的恐慌慎颗,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件言询,死亡現(xiàn)場離奇詭異俯萎,居然都是意外死亡,警方通過查閱死者的電腦和手機运杭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門夫啊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辆憔,你說我怎么就攤上這事撇眯”ㄇ叮” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵熊榛,是天一觀的道長锚国。 經常有香客問我,道長玄坦,這世上最難降的妖魔是什么血筑? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮煎楣,結果婚禮上豺总,老公的妹妹穿的比我還像新娘。我一直安慰自己择懂,他們只是感情好喻喳,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著休蟹,像睡著了一般沸枯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赂弓,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機與錄音哪轿,去河邊找鬼盈魁。 笑死,一個胖子當著我的面吹牛窃诉,可吹牛的內容都是我干的杨耙。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼飘痛,長吁一口氣:“原來是場噩夢啊……” “哼珊膜!你這毒婦竟也來了?” 一聲冷哼從身側響起宣脉,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤车柠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后塑猖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竹祷,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年羊苟,在試婚紗的時候發(fā)現(xiàn)自己被綠了塑陵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜡励,死狀恐怖令花,靈堂內的尸體忽然破棺而出阻桅,到底是詐尸還是另有隱情,我是刑警寧澤兼都,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布嫂沉,位于F島的核電站,受9級特大地震影響俯抖,放射性物質發(fā)生泄漏输瓜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一芬萍、第九天 我趴在偏房一處隱蔽的房頂上張望尤揣。 院中可真熱鬧,春花似錦柬祠、人聲如沸北戏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗜愈。三九已至,卻和暖如春莽龟,著一層夾襖步出監(jiān)牢的瞬間蠕嫁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工毯盈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留剃毒,地道東北人。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓搂赋,卻偏偏與公主長得像赘阀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子脑奠,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355