一、Swift 内存 & 值语义(★★★★★)
Q21:struct 和 class 本质区别?
struct 是 值类型,存储在栈或 inline storage 中,赋值时发生 copy。
class 是 引用类型,存储在堆上,变量保存的是指针。
核心区别:
struct → 值语义
class → 引用语义
✅ 值语义带来线程安全
✅ 避免共享状态
Swift 优先推荐 struct 是为了 predictable state。
Q22:什么是 Copy-on-Write(COW)?
Copy-on-Write 是一种 延迟复制优化:
- 多个变量共享同一内存
- 当发生写操作时才真正复制
var a = [1,2,3]
var b = a // 未复制
b.append(4) // 此时复制
通过 isKnownUniquelyReferenced 判断引用唯一性。
为什么 Swift Array 性能高?
因为 COW 避免不必要复制。
Q23:struct 一定在栈上吗?
struct 不一定在栈上,它的存储位置由编译器决定,可能在栈、堆甚至寄存器中。比如作为局部变量时通常在栈上,但如果作为 class 的成员或者被闭包捕获,可能会分配在堆上。本质上,struct 的核心是值语义,而不是具体的内存位置,这一点和 class 的引用语义是本质区别
Q24:mutating 关键字作用?
因为 struct 是值类型。
mutating 表示:方法内部允许修改 self。
本质:
self = newSelf
二、Swift Dispatch 机制(🔥 高频杀手)
| 类型 | dispatch |
|---|---|
| class override | dynamic |
| protocol extension | static |
| final | static |
| generic | static |
Q26:protocol extension 为什么可能不走重写?
protocol extension 默认是 static dispatch。
只有 protocol requirement 才是 dynamic dispatch。
protocol A {
func test()
}
extension A {
func test() { print("A") }
}
调用取决于类型声明方式。
Swift 优先静态派发提升性能。
三、Closure(★★★★★)
Q27:closure 捕获变量还是值?
捕获的是变量引用(capture by reference)。
var a = 10
let c = { print(a) }
a = 20
c() // 20
Q28:[weak self] 原理?
closure 捕获:
weak reference -> side table
避免 closure strong 持有 self。
capture list 在 closure 创建时执行。
Q29:escaping closure 是什么?
closure 生命周期逃离当前函数作用域。
例如:
- 网络回调
- async 执行
为什么需要标记?
因为:
编译器需要改变内存管理策略。
四、泛型(8 年高频)
Q30:泛型优势?
- 代码复用
- 类型安全
- 编译期检查
- 无 runtime casting
Q31:associatedtype 是什么?
用于 protocol 中定义占位类型。
protocol Container {
associatedtype Item
}
Q32:为什么不能直接用带 associatedtype 的 protocol?
因为:
编译器无法确定具体类型大小。
所以需要:
👉 Type Erasure
Q33:什么是 Type Erasure?
把具体泛型类型隐藏为统一类型。
AnySequence
AnyPublisher
核心思想:
用 box 包装真实类型。
一句话:
抹去泛型信息以统一接口。
五、Swift Concurrency(现在面试必问)
Q34:async/await 解决什么问题?
- callback hell
- 可读性差
- 错误传播困难
- 让异步代码像同步代码。
Q35:async/await 本质是多线程吗?
是协程(cooperative concurrency)。
任务可挂起,不阻塞线程。
Q36:Task 是什么?
Task 是 Swift 并发的基本执行单元。
类似轻量级协程。
Q37:Task 和 GCD 区别?
| Task | GCD |
|---|---|
| 结构化并发 | 手动管理 |
| 自动取消传播 | 无 |
| async/await | callback |
Q38:什么是 Structured Concurrency?
子任务生命周期绑定父任务。
父取消 → 子全部取消。
Q39:Actor 为什么线程安全?
Actor 内部状态一次只允许一个任务访问。
actor mailbox queue
串行执行。
一句总结:
Actor = async + serial queue + state isolation
Q40:MainActor 作用?
保证代码运行在主线程。
@MainActor
class ViewModel {}