OC 对象的本质
最近时间充足,打算再次对 Object-C 进行分析,而 Object-C本身绝对是优雅和美丽的,所以从这里开始,我们和Object-C来一场美丽的邂逅!
一、认识Object-C对象
Object-C本质
- 我们平常编写的Object-C代码,底层其实都是C/C++代码,编译器再编译成汇编,最终形成机器语言
- 对象、类 主要是基于C/C++结构体实现
那么一个Object-C对象在底层中如何布局的?通过分析不难发现其底层实现如下图
1 | struct NSObject_IMPL{ |
内存初窥
- 一个Object-C对象会被分配不少于 16 bytes 的空间
- 对象的指针地址为第一个成员的地址
- 遵守内存对其原则
可能你对最小分配16字节大小的结论有疑问,可以点击 objc4/ 下载源码查看内部实现 。在 objc-class-old 文件的 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone) 方法中实现了下面规定
1 | _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone) |
内存对齐又是怎么一回事? 看看官方说明一解疑惑
1 | // Class's ivar size rounded up to a pointer-size boundary. |
二、Object-C对象创建原理
官方给出了两种创建对象的方式,方式一:通过 [[object alloc]init]
,方式二:通过 [object new]
下面我们用两种方式来新建一个 Person
对象一探究竟。
1 | Person * person = [[Person alloc] init]; |
简单的一次调用,其背后原理为何?
我将调用 alloc
整个源码流程贴出方便大家比对
2.1 源码处理流程
- 先调用 objc_alloc ,此处会去调用
callAlloc
函数,注意后两个参数
1 | // Calls [cls alloc]. |
- 那么跳转到
callAlloc
函数 系统又处理了什么逻辑呢?
1 | // Call [cls alloc] or [cls allocWithZone:nil], with appropriate |
在第二步中存在两种调用关系,一种是存在最优化捷径 则直接调用
rootAllocWithZone
方法;一种则是在非objc2
下 实现allocWithZone
或者alloc
函数。在源码中官方直接去调用
_class_createInstanceFromZone
函数申请存储空间有兴趣的同仁可以跟踪下源码看看官方怎么进行存储空间开辟的,这里你会对前面内存初窥
中写道的结论有个深刻的认识。1
2
3
4
5
6_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
// allocWithZone under __OBJC2__ ignores the zone parameter
return _class_createInstanceFromZone(cls, 0, nil,
OBJECT_CONSTRUCT_CALL_BADALLOC);
}对于
alloc
方法 系统实现起来就显得不那么复杂了1
2
3
4+ (id)alloc {
return _objc_rootAlloc(self);
}
2.2 init 原理
分析完了 alloc
的流程,我们接着分析 init
的流程。相比于 alloc
来说, init
内部实现十分简单,先来到的是 _objc_rootInit
,然后就直接返回 obj
了。其实这里是一种抽象工厂设计模式的体现,对于 NSObject
自带的 init
方法来说,其实啥也没干,但是如果你继承于 NSObject
的话,然后就可以去重写 `initWithxyz 之类的初始化方法来做一些初始化操作。
1 | // Replaced by CF (throws an NSException) |
三、总结
开发过程中探究源码会让我们对一项事务有不一样的认识,建议同仁多阅读源码。
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章