玄铁弱引用编程指南
弱引用是打破 ARC 循环引用的关键机制。当一个对象被弱引用时,它不增加引用计数——当所有强引用释放后,对象被回收,弱引用自动置为 空。
为什么需要弱引用?
循环引用问题
当两个对象互相强引用时,它们的引用计数永远不会降到零,导致内存泄漏:
xuantie
型 父节点 {
设 子: 子节点 // 强引用子节点
}
型 子节点 {
设 父: 父节点 // 强引用父节点——形成循环!
}
设 p = 造 父节点()
设 c = 造 子节点()
p.子 = c
c.父 = p
// p 和 c 互相持有,即使不再使用也不会释放——内存泄漏用弱引用打破循环
将其中一条边改为弱引用,循环即被打破:
xuantie
型 子节点 {
弱 设 父: 父节点? // 弱引用父节点——不增加引用计数
}弱引用语法
局部变量弱引用
xuantie
设 强引用 = "Hello 玄铁"
弱 设 观察者 = 强引用 // 弱引用局部变量
示("观察者: #{观察者}") // "Hello 玄铁"
强引用 = "新对象" // 唯一强引用被覆盖
示("观察者: #{观察者}") // "空"——原对象已释放,弱引用自动归零类成员字段弱引用
xuantie
型 子节点 {
弱 设 父: 父节点? // 弱引用类成员
设 名称: 字
函 造(p, n) {
此.父 = p // 赋值操作——不 retain
此.名称 = n
}
}
型 父节点 {
设 子列表: 数组<子节点> // 强引用子节点列表
// ...
}重赋值与 弱引用 = 新值
xuantie
弱 设 观察者 = 对象A
观察者 = 对象B // 直接覆盖(不 release 旧值,不 retain 新值)配合可空类型 ?
弱 修饰的字段应使用可空类型,因为引用的对象随时可能被释放而变空:
xuantie
型 子节点 {
弱 设 父: 父节点? // ✅ 正确:? 表明父可能为空
// 弱 设 父: 父节点 // ⚠️ 警告 W005:缺少可空修饰符
}编译器会对不含
?的弱引用字段输出 W005 警告(严格模式→错误)。
ARC 行为详解
弱引用声明时的 ARC 操作
xuantie
弱 设 观察者 = 强引用底层发生:
- 加载
强引用的值→表达式自动 retain→ref+1 xt_weak_init(观察者_addr, 值)——将 alloca 地址注册到对象的弱引用链表xt_release(值)——抵消步骤 1 的 retain→ref 回到只有强引用持有的状态- 存储值到 alloca(不 retain)
对象释放→弱引用归零链路
强引用 = 新对象(赋值)
→ xt_release(旧对象), refcount: 1→0
→ xt_free_obj(旧对象)
→ xt_weak_clear(旧对象)
→ 遍历全局弱引用链表
→ *slot_addr = XT_NULL(归零!)类成员弱引用归零
// c.父 是弱引用,指向 p
p = 空(或 p 离开作用域)
→ xt_release(p), refcount: 1→0
→ xt_free_obj(p)
→ xt_weak_clear(p)
→ xt_dict_set_weak(c实例, "父", XT_NULL)
→ c.父 变为 空 ✅常见模式
父子关系(父强引用子,子弱引用父)
xuantie
型 父 {
设 子: 子节点? // 强引用
}
型 子 {
弱 设 父: 父节点? // 弱引用——打破循环
}观察者模式
xuantie
设 数据源 = "数据"
弱 设 监听者 = 数据源 // 监听但不持有
// ... 数据源被重新赋值后,监听者自动变空委托模式
xuantie
型 视图 {
弱 设 代理: 代理口? // 弱引用代理——避免视图持有控制器
}当前局限
| 局限 | 说明 |
|---|---|
| 弱引用重赋值旧槽位校验 | xt_weak_clear 清零前已校验 *slot==obj(防误清零),但旧槽位未从链表摘除 |
| 闭包弱捕获未支持 | 函() [弱 此] { ... } 语法尚未实现 |
完整示例
xuantie
示("--- 弱引用完整示例 ---")
// 定义父子类型
型 父节点 {
设 名称
设 子列表
函 造(n) {
此.名称 = n
此.子列表 = []
}
}
型 子节点 {
弱 设 父: 父节点?
设 名称
函 造(p, n) {
此.父 = p
此.名称 = n
}
}
// 创建对象
设 p = 造 父节点("根")
设 c = 造 子节点(p, "叶子")
p.子列表.追加(c)
// 验证弱引用工作
示("子节点引用父: " & c.父.名称)
// 验证类成员弱引用归零(关键:不要用中间变量保留父引用)
p = 空
示("释放后归零: #{c.父 == 空}") // 真:xt_weak_clear 自动清零更完整的工程实例请参阅:examples/weak_ref/文档树.xt —— 7 节点文档树结构,覆盖局部/类成员弱引用、归零、重赋值、ARC 独立性、W401 检测。
下一篇:05_模块系统.md