# 玄铁弱引用编程指南

弱引用是打破 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
弱 设 观察者 = 强引用
```

底层发生:
1. 加载 `强引用` 的值→表达式自动 retain→ref+1
2. `xt_weak_init(观察者_addr, 值)`——将 alloca 地址注册到对象的弱引用链表
3. `xt_release(值)`——抵消步骤 1 的 retain→ref 回到只有强引用持有的状态
4. 存储值到 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](https://github.com/MARKJY-China/XuanTie-Lang/blob/master/examples/weak_ref/%E6%96%87%E6%A1%A3%E6%A0%91.xt) —— 7 节点文档树结构,覆盖局部/类成员弱引用、归零、重赋值、ARC 独立性、W401 检测。

---

*下一篇:[05_模块系统.md](./05_模块系统.md)*