OC底层源码/原理合集
建议先看下 IOS底层(三): alloc相关1.初探 alloc, init, new源码分析
先看个例子
NSObject
, alloc
方法里面 加断点, 运行我们会发现竟然没有走+ (id)alloc
方法
那么NSObject在走的是哪个方法呢?
打开 Debug
→Debug Workflow
勾选 Always Show Disassemly
进行汇编调试
alloc方法这边打个断点, 运行一下
我们可以看到都走了一个objc_alloc
方法
全局搜索 objc_alloc
,可看到有一个这个方法
在objc_alloc
中加一个断点,先暂时关闭汇编, 重新运行下可看到, 的确走到这里来了
那么为什么NSObject
走的是objc_alloc(Class cls)
这个方法?
原因主要是: NSObject
系统级别帮我们走完
这里我们需要一份LLVM
源码(llvm-project
, 是系统级别的源码)来具体分析下, objc_alloc
是什么时候有的, 而它又与alloc
有什么区别。
LLVM下载地址
查找下
通过alloc字符串
或者omf_alloc:
搜索, 找到tryGenerateSpecializedMessageSend
方法
这里可以看到, 如果当前方法sel
如果是alloc
就会调用一个EmitObjCAlloc
方法, 点进去看一下
可以看到这里调用了一个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_alloc
→ callAlloc
并不应该走
alloc
→_objc_rootAlloc
→_objc_rootAlloc
→callAlloc
我们在callAlloc
打个断点发现, 的确是走了2次, 这就很离谱?
我们在 callAlloc
跟一下流程
可看到自定义类中objc_alloc
, callAlloc
走的是(id, SEL))objc_msgSend)(cls, @selector(alloc));
, 即向系统发送消息, 没有走_objc_rootAllocWithZone
这里我们需要再看下LLVM
中 GeneratePossiblySpecializedMessageSend
消息发送这里
我们可以看到但凡是runtime
的消息发送必然现在走if
判断, 由于传入sel
是@selector(alloc)
并没有走过, 没有找到所以这里的if
判断是false
, 走GenerateMessageSend
这个方法, 即调用sel
→alloc
方法, 即alloc
→_objc_rootAlloc
→_objc_rootAlloc
→callAlloc