Lesson 4 / 6

生命周期与序列化安全

Unity 新人最常见的坑:对象会启用、禁用、销毁;字段名和 Inspector 引用会被序列化保存。

建议时长 10–12 min重点:隐性状态练习:找 bug

生命周期最小集

页面从出现到消失

Awake对象加载
OnEnable订阅 / 启动
Start首次刷新
Update每帧,高频
OnDisable取消 / 停止
OnDestroy销毁

异步请求可能跨过 OnDisable / OnDestroy 返回。验收必须覆盖“关闭页面后不再改 UI”。

方法什么时候发生适合做什么
Awake对象被加载时初始化内部状态,获取自身组件。
OnEnable对象每次启用订阅事件、注册回调、启动临时任务。
Start第一次 Update 前依赖其他对象已初始化后的首刷。
Update每帧调用极少量实时逻辑;不要做网络请求、IO、大量查找。
OnDisable对象每次禁用取消订阅、取消请求、停止临时任务。
OnDestroy对象销毁释放资源,兜底清理。
后台迁移提醒: 不要把 Unity 页面当成长生不死的 singleton。用户可以关闭页面,Scene 可以切换,对象可以被对象池复用。

HappyMahjong 中的生命周期锚点

事件订阅必须成对

private void OnEnable()
{
    _service.Changed += HandleChanged;
}

private void OnDisable()
{
    _service.Changed -= HandleChanged;
}

如果只订阅不取消,第二次打开页面可能重复回调;页面关闭后也可能访问已经销毁的 UI。

异步必须考虑页面关闭

private CancellationTokenSource _loadCts;

private void OnEnable()
{
    _loadCts = new CancellationTokenSource();
    _ = LoadAsync(_loadCts.Token);
}

private void OnDisable()
{
    _loadCts?.Cancel();
    _loadCts?.Dispose();
    _loadCts = null;
}

不要求产品同学会写这段代码,但要会把它写进验收:请求中关闭页面,不应再弹错误或改 UI。HappyMahjong 里还要关注 TSDK 回调、Command dispatch 和弹窗关闭后的残留回调。

Inspector 序列化风险

代码字段和 Inspector 引用是绑在一起的

C# 字段名
loginButton
Inspector 引用
Scene / Prefab 中保存的对象引用

字段重命名不是纯代码重构。旧序列化数据可能找不到新字段名。

Unity 可以把字段保存到 Scene / Prefab / Asset 中:

[SerializeField] private Button loginButton;
[SerializeField] private TMP_InputField usernameInput;

// HappyMahjong 中也可能有点击接收对象或弹窗引用:
[SerializeField] private GameObject emptyClick;
[SerializeField] private GameObject rewardPopup;

如果 agent 把字段名从 loginButton 改成 submitButton,旧 Inspector 绑定可能丢失。安全做法是检查是否需要:

using UnityEngine.Serialization;

[FormerlySerializedAs("loginButton")]
[SerializeField] private Button submitButton;

课堂练习:找出两个风险

private async void LoadUser()
{
    var user = await _service.LoadUserAsync();
    nameText.text = user.Name;
}

期望答案:

Retrieval check

重命名 `[SerializeField]` 字段前,最该检查什么?

Primary source

课后阅读 Unity 官方 MonoBehaviourserialization 文档。项目内优先读 Docs/01-flows/startup-flow.mdDocs/01-flows/login-flow.md。课堂只要求记住两件事:生命周期会反复发生,Inspector 引用和 StrangeIoC 绑定都是项目状态的一部分。

Ask the agent: “请专门检查这次修改是否有生命周期、异步取消、对象销毁后访问、序列化字段兼容性和 StrangeIoC binding 风险。”