一、alloc、init、new源码笔记

本文由快学吧个人写作,以任何形式转载请表明原文出处。

一、需要的资料

objc4-876,地址 : github.com/apple-oss-d...

二、探索的思路

1、要探索alloc和init和new具体做了什么,就需要知道什么时候我们用alloc和new,这个很容易,OC中一个对象的初始化最常用的就是 [[Obj alloc] init]和[Obj new],所以,第一步我们需要一个类,并且初始化一个对象。

2、要看alloc、init和new分别做了什么,就需要把它们分开来看。

3、我们最常用也是最基本最常见的类就是NSObject,我们创建的一些基本的类大多都继承于它,所以我们以NSObject的alloc、init和new方法来探索。

3、找到NSObject的源码,进行探索。

三、需要的基本知识储备

字节对齐 :

1、为什么要字节对齐

因为苹果官方要求的。

2、为什么要这么要求

不止是苹果官方,几乎所有的语言,都会要求内存对齐。

如下图 :

首先,我们存储数据的目的不是单纯的存储,而是要在需要的时候可以调用,而cpu是不是以字节为单位来读取数据的,而是以"块"为单位。

如果所有申请内存空间的数据都要这样去申请,并且拿到不同大小的内存空间去使用。

那么在我们再调用这些数据的时候,cpu要不断的变换读取数据的内存长度大小,来精准的获取数据,这是很浪费资源的行为。

所以,字节对齐,实际上是一种以空间换取时间的方式,让cpu更高效的读取内存中的数据。

3、iOS的字节对齐

iOS的字节对齐是以16字节为基本数,开辟内存空间的大小需要是16的整数倍。

为什么iOS要以16字节进行字节对齐?

因为OC对象中,第一位一定有一个isa指针,而isa指针的大小就是8字节,如果仅仅以8字节进行字节对齐,如果两个对象都是没有其他任何属性的对象(仅仅有isa指针),那么这两个对象的内存空间就会挨在一起,就容易造成数据的混乱。

iOS也有对8字节对齐的要求,具体的详情在下面的苹果官方字节对齐算法代码那里有解释。

4、苹果官方的字节对齐算法

c 复制代码
static inline size_t align16(size_t x) {
    return (x + size_t(15)) & ~size_t(15);
}

四、alloc

1、alloc方法的跳转

1、打开准备的资料 : objc4-876的文件。

2、在Xcode的Navigators搜索alloc {,因为方法的实现都是以 { 来开始的,所以带上 { 可以省略很多麻烦。

3、在NSObject.mm文件找到 alloc的实现方法。.mm格式文件是为了支持C++和OC的混编。

4、进入_objc_rootAlloc方法。

5、进入callAlloc方法。

到这里我们可以发现,alloc的实现方法,一定是在callAlloc中提到的_objc_rootAllocWithZone或者allocWithZone方法。

如果可以断点调试的话,可以发现,实际上JDPersonalloc方法进入的是第二个if,也就是fastpath的判断里面,进入了_objc_rootAllocWithZone方法。

2、alloc的核心实现

1、在搜索栏搜索_objc_rootAllocWithZone(找到方法的实现。

2、进入_class_createInstanceFromZone方法。

这里保留一下传入的参数,以便探索。这里可以进入一下OBJECT_CONSTRUCT_CALL_BADALLOC,这个参数看一下,发现是一个枚举值,是2。所以传入的参数就是(cls, 0, nil, 2)。

3、_class_createInstanceFromZone方法的实现

3、alloc申请内存中的一些细节

1、如何计算申请内存的对象所需内存空间的大小?

这一步在_class_createInstanceFromZone方法中进行了实现,看上图中的

ini 复制代码
size = cls->instanceSize(extraBytes);

这里的size就是所需内存空间的大小,计算所用到的方法是instanceSize。直接进入instanceSize方法。

2、计算内存大小

重点在fastInstanceSizealignedInstanceSize

fastInstanceSize重点在align16 :

alignedInstanceSize重点在word_align :

3、align16word_align的源码

就是字节对齐的算法代码。

这里有一点,两个字节对齐的算法,一个是8字节对齐,一个是16字节对齐。

原因是8字节对齐的受众是对象内部的属性,对象内部的属性需要遵循8字节对齐的原则,而16字节对齐的受众则是对象。

比如 : obj1和obj2之间需要满足16字节对齐,而obj1的内部属性attr1和attr2需要满足8字节对齐。

五、init

和alloc同样,在objc4-876源码中找init的实现,在Xcode的Navigators搜索init {,找到NSObject.mm文件中的init实现。

类方法直接返回self,没有做任何的操作。实例方法调用_objc_rootInit,看一下 :

一样直接返回self。

其实init的意义在官方的注释中已经表达清楚了,init就是工厂模式,为了给开发者在实际的应用中提供一个自己可以自定义的接口。

六、new

源码查找方法同上。

new直接调用了callAlloc方法,和alloc的区别就是alloc调用的是_objc_rootAlloc方法,然后又_objc_rootAlloc调用的callAlloc,再就是传递的最后一个形参不一样。
new会直接调用init方法,如果我们自己定义一些init的方法,类似于initWith之类的,new只会调用init,而不会调用我们的init方法,所以用的比较少。

七、总结

1、alloc申请内存,字节对齐,绑定isa,核心方法是callAlloc(实际入口),instanceSize(计算开辟内存的大小),calloc(申请内存,返回地址指针),initIsa(绑定isa)。

2、init提供重写的机会,给开发者根据自身情况做自定义。

3、new直接调用了alloc的实际入口callAlloc方法,然后调用了init方法。不会调用我们自定义的一些类似于initWith的方法。

相关推荐
iFlyCai2 小时前
Xcode 16 pod init失败的解决方案
ios·xcode·swift
郝晨妤11 小时前
HarmonyOS和OpenHarmony区别是什么?鸿蒙和安卓IOS的区别是什么?
android·ios·harmonyos·鸿蒙
Hgc5588866611 小时前
iOS 18.1,未公开的新功能
ios
CocoaKier13 小时前
苹果商店下载链接如何获取
ios·apple
zhlx283515 小时前
【免越狱】iOS砸壳 可下载AppStore任意版本 旧版本IPA下载
macos·ios·cocoa
XZHOUMIN1 天前
网易博客旧文----编译用于IOS的zlib版本
ios
爱吃香菇的小白菜1 天前
H5跳转App 判断App是否安装
前端·ios
二流小码农1 天前
鸿蒙开发:ForEach中为什么键值生成函数很重要
android·ios·harmonyos
hxx2211 天前
iOS swift开发--- 加载PDF文件并显示内容
ios·pdf·swift
B.-2 天前
在 Flutter 应用中调用后端接口的方法
android·flutter·http·ios·https