IOS底层(五): alloc相关: NSObject, alloc源码分析

OC底层源码/原理合集

建议先看下 IOS底层(三): alloc相关1.初探 alloc, init, new源码分析

先看个例子


exp1
exp2

NSObject , alloc方法里面 加断点, 运行我们会发现竟然没有走+ (id)alloc方法

那么NSObject在走的是哪个方法呢?

打开 DebugDebug Workflow勾选 Always Show Disassemly进行汇编调试

alloc方法这边打个断点, 运行一下

exp3
exp4

我们可以看到都走了一个objc_alloc 方法
全局搜索 objc_alloc,可看到有一个这个方法

exp5

objc_alloc中加一个断点,先暂时关闭汇编, 重新运行下可看到, 的确走到这里来了

exp6

那么为什么NSObject走的是objc_alloc(Class cls) 这个方法?

原因主要是: NSObject 系统级别帮我们走完

这里我们需要一份LLVM源码(llvm-project, 是系统级别的源码)来具体分析下, objc_alloc是什么时候有的, 而它又与alloc有什么区别。
LLVM下载地址

查找下
通过alloc字符串或者omf_alloc:搜索, 找到tryGenerateSpecializedMessageSend方法

llvm查找alloc

这里可以看到, 如果当前方法sel如果是alloc就会调用一个EmitObjCAlloc方法, 点进去看一下

llvm查找alloc

可以看到这里调用了一个objc_alloc。由此可以得出NSObject中的alloc会走到objc+alloc, 其实这部分是由系统级别的消息处理逻辑, 固NSObject的初始化是由系统完成, 因此不会走传统的alloc的源码中。

j接下来我们看下自定义类SATest

NSObject *objc = [NSObject alloc];
SATest *objc1 = [SATest alloc];

首先SATest 是继承NSObject的, NSObject是其根类/基类/父类, 所有自定义的类都继承于NSObject。

我们由LLVM已经得出, NSObject都会走一个objc_alloc方法。那么继承于NSObject也会走一个objc_alloc方法。这个也是之前我们那张汇编的图片SATest, 也走了objc_alloc原因

那么问题也出现了
objc_alloccallAlloc 并不应该走
alloc_objc_rootAlloc_objc_rootAlloccallAlloc

我们在callAlloc打个断点发现, 的确是走了2次, 这就很离谱?

自定义类的callAlloc走了2次

我们在 callAlloc跟一下流程

自定义类objc_alloc走的是objc_msgSend

可看到自定义类中objc_alloc, callAlloc走的是(id, SEL))objc_msgSend)(cls, @selector(alloc));, 即向系统发送消息, 没有走_objc_rootAllocWithZone

这里我们需要再看下LLVMGeneratePossiblySpecializedMessageSend消息发送这里

llvm消息发送

我们可以看到但凡是runtime的消息发送必然现在走if判断, 由于传入sel@selector(alloc)并没有走过, 没有找到所以这里的if判断是false, 走GenerateMessageSend这个方法, 即调用selalloc方法, 即alloc_objc_rootAlloc_objc_rootAlloccallAlloc

总结:

NSObject
7EB02DAA0F471DC24E29A22E94C6A505.jpg
自定义类
image.png

你可能感兴趣的:(IOS底层(五): alloc相关: NSObject, alloc源码分析)