Unity中订阅事件时Destroy(gameObject)仅生效一次的问题求助
解决Unity中静态事件订阅引发的MissingReferenceException问题
首先咱们来理清楚问题根源:你用Lambda表达式订阅了静态事件OnChangeScene,第一次点击触发事件时,Destroy(gameObject)成功销毁了当前的Animal对象。但静态事件的生命周期和整个程序绑定,不会自动移除已销毁对象的订阅——也就是说,这个Lambda还挂在事件列表里。下次点击触发事件时,代码会尝试执行这个已经失效的Lambda,而此时Animal对象已经被销毁,访问它的gameObject就会抛出那个MissingReferenceException。
接下来给你两种可行的解决方案:
方案一:对象销毁前取消订阅(推荐)
因为Lambda表达式是匿名的,直接取消订阅需要先把它保存为一个变量。修改第二个脚本的代码如下:
// 先保存Lambda的引用,方便后续取消订阅 private Action _sceneChangeHandler; private void Start() { _sceneChangeHandler = () => Destroy(gameObject); MoveButton.OnChangeScene += _sceneChangeHandler; } private void OnDestroy() { // 对象销毁时,从静态事件中移除订阅 if (_sceneChangeHandler != null) { MoveButton.OnChangeScene -= _sceneChangeHandler; } }
这样一来,当Animal对象被销毁时,OnDestroy会自动把订阅从静态事件里移除,后续触发事件时就不会再执行这个无效的Lambda了,也就不会报错。
方案二:在Lambda中增加有效性检查
如果你暂时不想修改订阅逻辑,也可以在Lambda里先判断对象是否还能被访问:
private void Start() { MoveButton.OnChangeScene += () => { // 先检查当前对象是否未被销毁 if (this != null && gameObject != null) { Destroy(gameObject); } }; }
不过这种方法只是避免了报错,失效的订阅仍然会留在静态事件列表里,长期下来可能造成内存浪费,所以更推荐方案一。
内容的提问来源于stack exchange,提问作者Sean Carey
相关产品推荐
相关产品推荐

