Unity Fishnet OnStopClient偶发MissingReferenceException问题求助
问题描述
使用Fishnet的OnStartClient和OnStopClient方法时遇到异常:
- 启动客户端时通过
GameObject.FindGameObjectWithTag("InventoryPanel")获取对应GameObject并赋值给invPanel - 停止客户端时访问
invPanel,尝试判断其激活状态并设置为激活 - 测试发现:每次启停客户端3次,前两次触发
MissingReferenceException(提示对象已销毁仍被访问),第三次却能正常运行,不符合预期的“始终正常/始终异常”结果
相关代码片段:
public override void OnStopClient() { base.OnStopClient(); // 此处有时会抛出空引用异常,前两次启停报错,第三次正常 // invPanel是在OnStartClient中通过GameObject.FindGameObjectWithTag("InventoryPanel")获取的 if (!invPanel.activeSelf) { invPanel.SetActive(true); } }
原因分析与解决方案
核心原因
- 僵尸引用残留:Unity中已销毁的对象不会自动将变量置为
null,invPanel可能持有已销毁对象的无效引用,此时访问其属性就会触发异常 - 生命周期顺序差异:前两次启停时,
OnStopClient的执行时机晚于InventoryPanel的销毁逻辑;第三次可能因对象复用、场景加载缓存等原因,InventoryPanel尚未被销毁,或重新获取到了有效引用
修复步骤
方案1:访问前严格检查引用有效性
Unity重载了==运算符,可直接判断对象是否已销毁或为空:
public override void OnStopClient() { base.OnStopClient(); // 先判断引用是否有效 if (invPanel == null) { // 尝试重新获取引用,避免缓存的引用失效 invPanel = GameObject.FindGameObjectWithTag("InventoryPanel"); // 仍找不到则直接返回 if (invPanel == null) return; } if (!invPanel.activeSelf) { invPanel.SetActive(true); } }
方案2:每次使用时重新查找(更稳妥)
放弃缓存引用,在OnStopClient中直接查找目标对象,彻底避免过期引用问题:
public override void OnStopClient() { base.OnStopClient(); GameObject invPanel = GameObject.FindGameObjectWithTag("InventoryPanel"); if (invPanel != null && !invPanel.activeSelf) { invPanel.SetActive(true); } }
额外优化建议
- 避免频繁使用
GameObject.FindGameObjectWithTag,可在客户端启动时将InventoryPanel注册到单例管理类,后续直接从单例获取,提升效率和可靠性 - 检查
InventoryPanel的销毁逻辑,确认是否在客户端停止时被不必要销毁;若需保留该对象,可添加DontDestroyOnLoad标记
内容的提问来源于stack exchange,提问作者Cody
相关产品推荐
相关产品推荐

