一、内存布局上的差异
1️⃣ 值类型(Value Type)
典型代表:struct、enum、tuple、基本类型(Int、Double)
📦 内存存储方式
-
直接存储数据本身
-
通常分配在:
- 栈(Stack) —— 局部变量
- 或作为成员嵌入到其它对象的内存中
-
不需要额外的间接层
struct Point {
var x: Int
var y: Int
}
let p = Point(x: 1, y: 2)
// p 的 x、y 连续存放在一块内存里
🧠 特点
- 内存布局连续、紧凑
- 访问速度快(无指针跳转)
- 拷贝语义明确(copy)
Swift 的标准库值类型(如
Array、Dictionary)内部会用 堆 + 引用计数,
但对外仍然表现为值语义(Copy-on-Write) 。
2️⃣ 引用类型(Reference Type)
典型代表:class、actor
📦 内存存储方式
-
对象本体分配在堆(Heap)
-
变量中存的是:
- 一个 指向堆对象的引用(指针)
class Person {
var name: String
}
let a = Person(name: "Tom")
let b = a
内存关系是:
a ──┐
├──> Heap 上的 Person 对象
b ──┘
🧠 特点
- 多个变量可指向同一对象
- 内存分配 / 释放成本更高
- 访问需要一次指针间接访问
二、ARC 管理机制上的差异
1️⃣ 值类型:❌ 不参与 ARC
-
没有引用计数
-
生命周期由:
- 作用域结束
- 栈帧销毁
- 或宿主对象释放
-
拷贝时直接复制值(或触发 COW)
var a = 10
var b = a
b = 20
// a 和 b 完全独立
✅ 不存在循环引用问题
2️⃣ 引用类型:✅ 由 ARC 管理
ARC(Automatic Reference Counting)负责:
- 跟踪对象被多少“强引用”持有
- 引用计数为 0 时释放对象
📌 引用规则
strong:默认,+1weak:不增加引用计数,可自动置 nilunowned:不增加引用计数,但不为 nil(有风险)
class A {
var b: B?
}
class B {
weak var a: A?
}
⚠️ 典型问题:循环引用
class A {
var b: B?
}
class B {
var a: A?
}
// A ↔ B,ARC 无法释放
必须用 weak / unowned 打破。
三、对比总结表(面试超好用)
| 维度 | 值类型 | 引用类型 |
|---|---|---|
| 代表 | struct / enum | class / actor |
| 内存位置 | 栈 / 内嵌 | 堆 |
| 变量保存内容 | 实际数据 | 对象引用 |
| 语义 | 拷贝语义 | 共享语义 |
| ARC 管理 | ❌ 不参与 | ✅ 参与 |
| 循环引用 | 不存在 | 可能存在 |
| 线程安全 | 天然更安全 | 需手动保证 |
四、一句话总结(面试必杀)
值类型直接存值、不走 ARC、生命周期简单;
引用类型存指针、由 ARC 管理、需要处理引用关系和循环引用问题。