本章要点主要探索
NSObject
的alloc
源码?为什么要探索NSObject
的源码呢, 上一篇手撕iOS底层02 -- 分析alloc&init&new不是分析过alloc
的源码了嘛, 通过实践得知,NSObject *objc = [NSObject alloc];
这行代码是不会直接走alloc
方法里的, 这也就和我们之前探索的自定义类alloc
流程有区别?所以这一章分析下NSObject
的alloc
和自定义类的alloc
有什么区别?
0x00 -- objc_alloc
在断点处,点击Debug --> Debug Workflow --> Always Show Disassembly
;
通过汇编调试得知:
-
NSObject
的alloc
之前会调用objc_alloc
,自定义类Test
也会先调用objc_alloc
;
系统级别就把NSObject
的初始化做了,所以NSObject
的alloc
的调用关系是:
alloc --> objc_alloc --> calloc --> _objc_rootAllocWithZone
而自定义类的调用关系是:
alloc --> objc_alloc --> calloc --> objc_msgSend(cls,alloc) --> alloc -- > calloc --> _objc_rootAllocWithZone
0x01 -- 分析自定义类调用俩次alloc
首先探究下,为什么自定义的类调用alloc
会直接走到objc_alloc
的方法内?
究其原因, 基于alloc
的特殊性,应该是LLVM
编译器帮我们做了函数指针跳转,所以找一份苹果开源的llvm-project
,看看其中是否可以找到一些蛛丝马迹❤️
- 搜索
objc_alloc
,找到如下所示,在当前文件由很多objc_alloc
关键字;一点一点往下捋;
- 再往下看,
shouldUseRuntimeFunctionForCombinedAllocInit
这个方法表示版本控制;
- 然后查找什么地方使用了版本控制。找到特殊消息发送
tryEmitSpecializedAllocInit
- 遇到不好查找的关键代码时,开启上帝视觉,当前查找关键字
omf-aloc
在下边会调用这个方法特殊消息发送方法tryGenerateSpecializedMessageSend
第一次会调用objc_alloc
,然后条件不成立,走GenerateMessageSend
普通消息发送,走到alloc
流程;So
自定义类的流程alloc
会走俩次,第一次发送alloc
会走到objc_alloc
,通过objc_alloc
走到callAlloc
消息发送,会再次走到alloc
源码里;
CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
bool isClassMessage) {
if (Optional SpecializedResult =
tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
Sel, Method, isClassMessage)) {
return RValue::get(SpecializedResult.getValue());
}
return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
Method);
}
这段代码是解释为什么走俩次
alloc
的, 在if
条件里的tryGenerateSpecializedMessageSend
这个函数一定会走, 从上可知,这个函数里有一个case
判断,如果是alloc
,会调用objc_alloc
,然后这个if
条件不成立, 会执行下边GenerateMessageSend
函数,执行普通的消息发送 ,走alloc
流程。
0x02 -- 附上流程图
-
NSObject alloc
流程图
- 自定义类
alloc
流程图