iOS app 加載流程
- 由 cpu 自硬盤中提取 app 數(shù)據(jù)流 加載至 內(nèi)存中
- 鏈接app運行需要的各種庫
- 執(zhí)行文件,啟動app
具體加載流程可參考下面這篇文章
iOS APP啟動性能優(yōu)化
object-c 相關(guān)本質(zhì)的探索
在日常開發(fā)中饰抒,對象,我們平時常用鸦采,那么對象的本質(zhì)是什么呢?
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Person : NSObject
- (void)run;
@end
NS_ASSUME_NONNULL_END
#import "Person.h"
@implementation Person
@end
#import <Foundation/Foundation.h>
#include <objc/runtime.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc]init];
[p run];
}
return 0;
}
如上剂癌,創(chuàng)建一個簡單當app温眉,含有一個 Person 類 ,在.m中并沒有實現(xiàn)該方法。當我們編譯當時候并不會報錯准夷,在app啟動后 會崩潰 ,這是為什么呢莺掠?
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o testmain.c++
在項目文件夾中使用如上命令衫嵌,來clang 一下 main.m
會產(chǎn)生一個很龐大當 c++文件,上面部分都是在引入相關(guān)資源文件彻秆,可以先不用看楔绞,來到最后面,我們會發(fā)現(xiàn) 在第 33249 行 有一個person IMP的結(jié)構(gòu)體唇兑,由此可見酒朵,對象的本質(zhì)是 結(jié)構(gòu)體。我們繼續(xù)往下看扎附,這里是main函數(shù)的入口蔫耽,代碼中
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc]init];
[p run];
}
return 0;
main函數(shù)我們只是創(chuàng)建了一個 Person 對象 這里
Person * p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("run"));
}
很長的一段代碼,我們?nèi)サ舾鞣N類型轉(zhuǎn)換
Person * p = (id, SEL)objc_msgSend(objc_msgSend)((objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));
(objc_msgSend)(p, sel_registerName("run"));
}
最后可以理解為:
Person 對象接受了一個 alloc 的方法 獲取到一個對象之后 該對象接受了一個 init 的方法 最后獲取到的對象賦值給了 p 然后 p 對象接受了一個 run 的消息
那么留夜,方法的本質(zhì)由此證明就是 消息發(fā)送