虽然这五个操作最终都会导致对象的“引用计数(Reference Count)”增加,但从所有权(Ownership)的哲学和内存物理演进来看,它们有着本质的区别。
我们可以把 alloc/new/copy/mutableCopy 归为一类,把 retain 归为另一类。
1. 核心区别:创建(Creation) vs. 共享(Sharing)
| 操作 | 本质行为 | 内存变动 | 所有权语义 |
|---|---|---|---|
alloc / new | 从无到有 | 在堆上分配全新的内存空间,初始化 isa 指针。 | “我是这块领地的造物主。” 你拥有这块新内存的原始所有权。 |
copy / mutableCopy | 克隆 | 产生一份现有对象的副本(通常是新内存,除非是不可变对象的 copy)。 | “我想要一份一模一样的,但互不干扰。” 你拥有副本的所有权,与原件脱离。 |
retain | 认领 | 仅将现有对象的引用计数 ,不分配新内存。 | “我也要用这个东西,请别在我用完前毁掉它。” 你与他人共享同一个对象的所有权。 |
2. alloc / new:所有权的起源
这是内存管理的起点。
alloc:它是底层class_createInstance的封装。它直接向系统申请一块大小为instanceSize的内存。new:它等同于[[Class alloc] init]。
本质: 你不仅拥有了所有权,还承担了**初始化(Initialization)**的责任。
3. copy / mutableCopy:所有权的独立
这两个操作体现了 “防御性编程” 的思想。
copy:如果你从外部接收一个字符串,你不确定对方是否会突然修改它。通过copy,你获得了一个属于你自己的、不可变的“快照”。mutableCopy:无论原对象是否可变,都会产生一个全新的、可变的对象。
本质: 这是一种**“断绝关系”**的所有权获取。修改新对象不会影响原对象。
4. retain:所有权的责任分担
retain 是 Objective-C 引用计数模型的灵魂。它不涉及任何内存的重新分配。
- 底层动作: 现代系统下,它只是修改了
isa指针里的extra_rc位(或者在哈希表SideTable里加 1)。 - 语义: 它代表了一种**“强引用”**。它告诉系统:“只要我不放手(
release),这个对象在内存里的物理存在就是合法的。”
5. 一个容易被忽略的细节:copy 的“伪创建”
对于不可变对象(如 NSString),调用 copy 实际上等同于 retain。
- 为什么? 因为既然对象不可变,克隆一份纯属浪费内存。
- 后果: 此时虽然语义上是“获取副本的所有权”,但物理上你依然是和别人“共享”同一块内存。这是编译器和运行时为了性能做的联合优化。
总结:如何准确判定?
- 如果你想要一个全新的个体 使用
alloc/new/copy。 - 如果你只是想延长某个已有对象的生命周期 使用
retain。
判定原则: 在 MRC 中,alloc/new/copy 拿到的对象,其 retainCount 初始就是 1;而 retain 是将现有的计数 。