这是我参与更文挑战的第3天,活动详情查看: 更文挑战
前言
iOS攻城狮应该都对alloc
比较熟悉,都知道是用来初始化对象的,但alloc
方法是到底是如何来初始化对象的,很多人都卡在这里,因为在项目是看不底层实现的,现在我们来用探究一下,用几种方式定位到alloc
方法实现所在的底层库
汇编
通过查看汇编代码可以找到对应的符号
方法
打开汇编调试,然后在alloc
方法打上断点
在汇编中找到objc_alloc
符号
然后加上对应的符号断点
然后跳到对应的符号断点
这里我们就可以看到alloc
所在底层库libobjc.A.dylib
step into
按住control
键,再点这个
也可以找到objc_alloc
alloc 底层流程
打开源码搜索alloc {
,看到alloc
底层调用了 _objc_rootAlloc
方法
再继深入
最新的都是使用的都__OBJC2
,
这地方的slowpath
fastPath
,跟编译的设置有有关
然后 !cls->ISA()->hasCustomAWZ
,没有分配指针则调用_objc_rootAllocWithZone
计算对象的大小,最小16字节
字节对齐算法,其实就是8字节对齐就是后三位抹零,就是8的倍数
,也可以通过左右移动来得到(size + 7) >> 3 << 3
calloc
分配内存在libmalloc
源码里,需要进步进行分析
然后就是通过initIsa
函数,初始化isa
然后将类与isa
进行绑定
isa
分为两种,一种是直接绑定了类,另一种是nonponterIsa
,因为isa
指针占用8位
也就是64bit
,避免浪费,所有isa
里存了类的地址外,还存有其他,这个需要进一步研究
这样我们就在开辟了一个内存来存储我们的对象了。
init, new 做了什么
init
在底层又做了什么呢
通过源码可以看出,init
什么也没做,直接返回了self
,所以inti
只是一种设计模式,为了方便开发者重写和在初始化的时候做一些事情
那new
跟alloc init
有什么区别呢
可以看出new
其实就相当于alloc init
,为了方便拓展传参还是尽量少使用new
来初始化对象
总结
言不胜图,下面为alloc
流程图
拓展
- 调用
alloc
,先调用的是objc_alloc
,而不是_objc_rootAlloc
, 汇编那里也看到了,而且会调用两次callAlloc
,这是因为调用alloc
,在进行消息转发的时候,llvm
第一所有的初始化方法做了拦截,被修正到了objc_alloc
下面是llvm
源码中的体现,可以看出当版本号大于8.0
就会调用objc_alloc
- 还有就是
NSObject
的objc_alloc
会在程序启动时调用一次,所以他和其他的类不太一样不会调用俩次callAlloc