[Unity] 物体的 activeInHierarchy = false 或脚本的 enable = false 时将物体销毁,OnDestroy 仍被调用

328 阅读2分钟

物体的 activeInHierarchy = false 或脚本的 enable = false 时将物体销毁,OnDestroy 仍被调用

看到一个人说 OnDestroy 有深坑

好在 Unity 给我们留下了许多实用的生命周期方法……以及一堆坑!

一个错误的(至少是有隐患的)做法是在 MonoBehavior.OnDestroy 方法中退订事件。因为当某个物体在场上处于未启用状态时被销毁,它的 OnDestroy 是不会被调用的!!!

具体而言是在以下几种操作时 OnDestroy 不会调用:

对该物体或其父物体调用 SetActive(false);

对该脚本设置了 enabled = false;

在运行时的 Inspector 中禁用了组件或其附属物体(或父物体)

我遇到的问题是,我订阅事件的物体处于未启用状态,此时加载切换至另一场景(自然销毁了所有订阅方,但OnDestroy 未被调用,即未正常退订事件)。另一方面,我的广播方是存在于全局跨场景的对象,因此当它再广播该事件时,残余的事件订阅引发了一连串的错误,查错的时候啪的一下很快啊,一天又过去了

————————————————

版权声明:本文为CSDN博主「mkr67n」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:blog.csdn.net/mkr67n/arti…

但是我又看到一个人是得出了 OnDestroy 不会受这些情况影响的结论

blog.csdn.net/suixinger_l…

于是我自己试了一下

测试类

新建一个测试类 TestMono.cs

public class TestMono : MonoBehaviour
{
    private void OnDestroy()
    {
        print("OnDestroy!");
    }
}

在其他任意 Mono 类里面测试这个 TestMono

1. 在挂载测试 Mono 的物体被禁用时,将该物体销毁

private void Start()
{
    StartCoroutine(TestCo());
}

private IEnumerator TestCo()
{
    GameObject testGameObject = new GameObject();
    testGameObject.AddComponent<TestMono>();
    testGameObject.SetActive(false);
    
    yield return new WaitForSeconds(5f);

    Destroy(testGameObject);
}

结果是测试 Mono 的 OnDestroy 被调用

2. 在挂载测试 Mono 的物体的父物体被禁用时,将该物体销毁

private IEnumerator TestCo()
{
    GameObject testGameObject = new GameObject();
    TestMono testMono = testGameObject.AddComponent<TestMono>();
    GameObject testParent = new GameObject();
    
    testGameObject.transform.parent = testParent.transform;
    testParent.SetActive(false);
    
    yield return new WaitForSeconds(5f);
    
    Destroy(testGameObject);
}

结果是测试 Mono 的 OnDestroy 被调用

综合 1 2,挂载测试 Mono 的物体的 activeInHierarchy = false 时,删去挂载测试 Mono 的物体, 测试 Mono 的 OnDestroy 会被调用

3. 在挂载测试 Mono 的物体的 Mono 脚本被禁用时,将该物体销毁

private IEnumerator TestCo()
{
    GameObject testGameObject = new GameObject();
    TestMono testMono = testGameObject.AddComponent<TestMono>();
    //testGameObject.SetActive(false);
    testMono.enabled = false;
    
    yield return new WaitForSeconds(5f);
    
    print(testMono.enabled);
    Destroy(testGameObject);
}

结果是测试 Mono 的 OnDestroy 被调用

综合 1 2 3,我感觉