方法:
通過前面一篇 從 MachO 加載到對(duì)象創(chuàng)建! 可以了解到 alloc
及 init
方法的底層, 接下來看方法的實(shí)質(zhì):
定義類 WXPerson
, 包含方法 run
;
創(chuàng)建 person 對(duì)象:
WXPerson * person = [[WXPerson all] init];
[person run];
通過編譯器編譯來看對(duì)象及方法的實(shí)質(zhì):
通過終端命令 clang -rewrite-objc main.m
可以獲得同級(jí)目錄下 main.cpp
文件, 查看文件發(fā)現(xiàn), 上面創(chuàng)建對(duì)象及調(diào)用方法被編譯成如下代碼:
由于代碼太長選擇圖片格式:
可以看到很多類型強(qiáng)轉(zhuǎn), 去掉類型強(qiáng)轉(zhuǎn):
WXPerson * person = objc_msgSend(
objc_msgSend(
objc_getClass("WXPerson"),
sel_registerName("alloc")),
sel_registerName("init"));
objc_msgSend(person,
sel_registerName("run"));
可以看到:
- 每次方法的調(diào)用都被編譯成了消息發(fā)送
objc_msgSend
; - 調(diào)用
alloc
類方法是通過objc_getClass
獲取類對(duì)象進(jìn)行調(diào)用; - @selector() 會(huì)編譯為
sel_registerName
方法, 向編譯器注冊(cè)一個(gè)方法;
補(bǔ)充: 由于該方法調(diào)用非常頻繁, 且 C / C++ 方法不能動(dòng)態(tài)保存方法的參數(shù), 需要通過匯編通過寄存器讀取動(dòng)態(tài)參數(shù), 所以蘋果把該方法用匯編實(shí)現(xiàn)(具體見 libobjc.A.dylib -> objc-msg-*.s):
前面文章已有涉及: +load VS +initialize
對(duì)象:
查看上面編譯好的 main.cpp 文件:
typedef struct objc_object WXPerson;
typedef struct {} _objc_exc_WXPerson;
struct WXPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
};
struct NSObject_IMPL {
Class isa;
};
可以發(fā)現(xiàn) WXPerson
類被編譯為 typedef struct objc_object WXPerson
結(jié)構(gòu)體
而 objc_object
定義如下:
typedef struct objc_class *Class;
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
typedef struct objc_object *id;
typedef struct objc_selector *SEL;
至此可以看出:
- 對(duì)象的本質(zhì)是結(jié)構(gòu)體;
- 對(duì)象包含一個(gè)指向
objc_class
結(jié)構(gòu)體的 isa; - 所以
id
可以代表一個(gè)對(duì)象;