用到的软硬件
1、Macbook Air
2、macOS Mojave 10.14.6
3、Xcode 11.3.1
4、Object-C(编程语言)
那么首先第一步我们先打开我们的macbook电脑,然后运行我们的xcode,创建我们的第一个工程,这里我就取名为alloc_init_test(如图)



废话说了好多进入正题吧,首先找到我们的main.m文件在里面添加代码,然后在确定我们的研究对象,以NSObject的alloc来研究,所以创建一个类来继承NSObject,这里我以创建Person的NSObject为例(至于为什么用NSObject 而不是 其他什么NSArray ,ViewCongroller为例,我只能抱歉,因为发现很多问题)
#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键,点击alloc再点击Jump to Definition,这时候会发现,这里虽然跳转到了,但是根本没办法读取到alloc这个函数是如何实现的。这个是因为苹果封装了alloc的实现函数,在一个包体里面。你只能看到alloc的在.h文件里面的定义。那么怎么办呢!!!
其实苹果在很久以前就开源了一部分的核心代码,那么我可以告诉大家我们这里的alloc的方法定义在objc4,那么大家问,为什么你会知道alloc的方法在objc4这个源码文件里面。很遗憾,我只能说,过程我也没有弄明白,所以我也不敢写出来。
首先
1、苹果开源源码地址:opensource.apple.com/tarballs/
2、给出别人已经编译好的iOS_objc4-756.2 最新源码编译调试,可以直接使用。
好这里我弄到了一份objc4-750的原生代码,并且配置好了可以直接运行我们的Person进行调试。也就是说在我们的原生代码里面,跑我们自己写的东西,可以看到原生里面实现的方法and过程。好像有点帅。。
在我们配置好的objc4-750代码里(ps:这里需要配置一个Target,不然进入不鸟断点哦,配置方式)
我这里配置了一个Alloctest的Target,配置完成后会生成一个Alloctest的文件夹,里面有一个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这里打入我们的断点。运行即可调试。
好,让我们一步一步的来追踪,
断点_push_01
+ (id)alloc {
//好像没有什么太多解释的东西
return _objc_rootAlloc(self);
}
断点_push_02
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
断点_push_03
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
if (slowpath(checkNil && !cls)) return nil;
//用于判断objective-c 版本,是不是2.0,目前我们使用的objective-c版本都是此版本。
#if __OBJC2__
//如果该对象没有自己的allocWithZone方法需要实现,这里我不懂
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
//查看一下类是否能快速分配内存
if (fastpath(cls->canAllocFast())) {
// No ctors, raw isa, etc. Go straight to the metal.
//查看一下类是否有析构函数
bool dtor = cls->hasCxxDtor();
//分配内存,给obj对象
id obj = (id)calloc(1, cls->bits.fastInstanceSize());
//如果分配失败,那么交给错误处理
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,则实现allocWithZone 方法
if (allocWithZone) return [cls allocWithZone:nil];
return [cls alloc];
}
这里有一个问题,就是关于这句话slowpath(checkNil && !cls)
,找了一堆的资料也不知所以然。跳进这个方法里面是一个宏定义
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
__builtin_expect这个指令是gcc引入的,作用是允许程序员将最有可能执行的分支告诉编译器。这个指令的写法为:__builtin_expect(EXP, N)。
意思是:EXP==N的概率很大。
好吧,这里我的理解只能是,提高编译效率。。。
这里参考了两篇文章
iOS——runtime(4):浅析对象的创建
iOS——runtime(5):allocWithZone剖析
好了 最后最后附上一张alloc的流程图。。。。

网友评论