为什么需要 weak let
?
需求场景 | weak var 的痛点 |
weak let 的新能力 |
---|---|---|
并发安全的 Sendable 类型 |
weak var 无法标记 Sendable |
✅ 可以 |
不可重新赋值的弱引用 | 仍可能被外部篡改 | ✅ 编译期禁止 |
值类型持有弱引用 | 无法保证不变性 | ✅ 完美支持 |
一句话:弱引用 + 不可变 = 更安全的所有权图。
语法速览
swift
final class Downloader: Sendable {
// 1️⃣ 一次性设置,之后不可改指向
weak let delegate: DownloaderDelegate?
init(delegate: DownloaderDelegate?) {
self.delegate = delegate
}
}
-
仍遵守 ARC:目标释放后自动变
nil
。 -
编译器禁止重新赋值:
downloader.delegate = AnotherVC()
// ❌ 直接报错。
完整示例:下载器 + 控制器
swift
protocol DownloaderDelegate: AnyObject {
func downloadDidUpdate(progress: Double)
}
final class Downloader: Sendable {
weak let delegate: DownloaderDelegate?
init(delegate: DownloaderDelegate?) {
self.delegate = delegate
}
func simulateDownload() {
delegate?.downloadDidUpdate(progress: 0.5)
}
}
final class ViewController: DownloaderDelegate {
func downloadDidUpdate(progress: Double) {
print("进度:\(progress)")
}
}
// MARK: - 测试
var vc: ViewController? = ViewController()
let downloader = Downloader(delegate: vc)
downloader.simulateDownload() // ✅ 打印 0.5
vc = nil
downloader.simulateDownload() // ✅ delegate 自动 nil,无崩溃
迁移清单:何时把 weak var
换成 weak let
场景 | 建议 |
---|---|
代理/回调 一次性设置 | 直接替换 |
单元测试需要多次赋值 | 保持 weak var |
值类型(struct)持有弱引用 | 立即使用 weak let |
actor / TaskGroup 内部 | 优先 weak let 以获得 Sendable 资格 |
实战:值类型快照
swift
struct UserSnapshot {
let name: String
weak let avatarLoader: AvatarLoader? // 不持有加载器
}
- 即使
avatarLoader
释放,UserSnapshot
依旧安全。 - 结构体可以跨线程传递,无需担心循环引用。
一句话总结
weak let
= "一次性弱引用",让 不可变性 与 ARC 安全 在同一行代码握手。
在并发、UI、快照场景里,它是 Swift 6.2 给你的"隐形护栏"。