用到的軟硬件
1、Macbook Air
2、macOS Mojave 10.14.6
3、Xcode 11.3.1
4、Object-C(編程語言)
那么首先第一步我們先打開我們的macbook電腦古拴,然后運(yùn)行我們的xcode,創(chuàng)建我們的第一個(gè)工程真友,這里我就取名為alloc_init_test(如圖)
廢話說了好多進(jìn)入正題吧黄痪,首先找到我們的main.m文件在里面添加代碼,然后在確定我們的研究對(duì)象盔然,以NSObject的alloc來研究桅打,所以創(chuàng)建一個(gè)類來繼承NSObject,這里我以創(chuàng)建Person的NSObject為例(至于為什么用NSObject 而不是 其他什么NSArray 愈案,ViewCongroller為例油额,我只能抱歉,因?yàn)榘l(fā)現(xiàn)很多問題)
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Person.h"
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
Person *p = [[Person alloc] init];
NSLog(@"%@",p);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
按住我們的cmmad鍵刻帚,點(diǎn)擊alloc再點(diǎn)擊Jump to Definition潦嘶,這時(shí)候會(huì)發(fā)現(xiàn),這里雖然跳轉(zhuǎn)到了崇众,但是根本沒辦法讀取到alloc這個(gè)函數(shù)是如何實(shí)現(xiàn)的掂僵。這個(gè)是因?yàn)樘O果封裝了alloc的實(shí)現(xiàn)函數(shù),在一個(gè)包體里面顷歌。你只能看到alloc的在.h文件里面的定義锰蓬。那么怎么辦呢!C袖觥芹扭!
其實(shí)蘋果在很久以前就開源了一部分的核心代碼麻顶,那么我可以告訴大家我們這里的alloc的方法定義在objc4,那么大家問舱卡,為什么你會(huì)知道alloc的方法在objc4這個(gè)源碼文件里面辅肾。很遺憾,我只能說轮锥,過程我也沒有弄明白矫钓,所以我也不敢寫出來。
首先
1舍杜、蘋果開源源碼地址:opensource.apple.com/tarballs/
2新娜、給出別人已經(jīng)編譯好的iOS_objc4-756.2 最新源碼編譯調(diào)試,可以直接使用既绩。
好這里我弄到了一份objc4-750的原生代碼概龄,并且配置好了可以直接運(yùn)行我們的Person進(jìn)行調(diào)試。也就是說在我們的原生代碼里面饲握,跑我們自己寫的東西私杜,可以看到原生里面實(shí)現(xiàn)的方法and過程。好像有點(diǎn)帥互拾。。
在我們配置好的objc4-750代碼里(ps:這里需要配置一個(gè)Target嚎幸,不然進(jìn)入不鳥斷點(diǎn)哦颜矿,配置方式)
我這里配置了一個(gè)Alloctest的Target,配置完成后會(huì)生成一個(gè)Alloctest的文件夾嫉晶,里面有一個(gè)main.m的文件骑疆,好了,你懂得替废,加入我們的Person類文件箍铭,并且在main.m里面添加代碼
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
Person *p = [[Person alloc] init];
NSLog(@"%@",p);
}
return 0;
}
然后在Person這里打入我們的斷點(diǎn)。運(yùn)行即可調(diào)試椎镣。
好诈火,讓我們一步一步的來追蹤,
斷點(diǎn)_push_01
+ (id)alloc {
//好像沒有什么太多解釋的東西
return _objc_rootAlloc(self);
}
斷點(diǎn)_push_02
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
斷點(diǎn)_push_03
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
if (slowpath(checkNil && !cls)) return nil;
//用于判斷objective-c 版本状答,是不是2.0冷守,目前我們使用的objective-c版本都是此版本。
#if __OBJC2__
//如果該對(duì)象沒有自己的allocWithZone方法需要實(shí)現(xiàn)惊科,這里我不懂
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
// No alloc/allocWithZone implementation. Go straight to the allocator.
// fixme store hasCustomAWZ in the non-meta class and
// add it to canAllocFast's summary
//查看一下類是否能快速分配內(nèi)存
if (fastpath(cls->canAllocFast())) {
// No ctors, raw isa, etc. Go straight to the metal.
//查看一下類是否有析構(gòu)函數(shù)
bool dtor = cls->hasCxxDtor();
//分配內(nèi)存拍摇,給obj對(duì)象
id obj = (id)calloc(1, cls->bits.fastInstanceSize());
//如果分配失敗,那么交給錯(cuò)誤處理
if (slowpath(!obj)) return callBadAllocHandler(cls);
//初始化obj的isa
obj->initInstanceIsa(cls, dtor);
return obj;
}
else {
// Has ctor or raw isa or something. Use the slower path.
id obj = class_createInstance(cls, 0);
if (slowpath(!obj)) return callBadAllocHandler(cls);
return obj;
}
}
#endif
// No shortcuts available.
//如果allocWithZone 為true馆截,則實(shí)現(xiàn)allocWithZone 方法
if (allocWithZone) return [cls allocWithZone:nil];
return [cls alloc];
}
這里有一個(gè)問題充活,就是關(guān)于這句話slowpath(checkNil && !cls)
,找了一堆的資料也不知所以然蜂莉。跳進(jìn)這個(gè)方法里面是一個(gè)宏定義
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
__builtin_expect這個(gè)指令是gcc引入的,作用是允許程序員將最有可能執(zhí)行的分支告訴編譯器混卵。這個(gè)指令的寫法為:__builtin_expect(EXP, N)映穗。
意思是:EXP==N的概率很大。
好吧淮菠,這里我的理解只能是男公,提高編譯效率。合陵。枢赔。
這里參考了兩篇文章
iOS——runtime(4):淺析對(duì)象的創(chuàng)建
iOS——runtime(5):allocWithZone剖析
好了 最后最后附上一張alloc的流程圖。拥知。踏拜。。