熟悉了cocos语法的都知道cc.isValid这个api可以判断节点/组件是否可用(是否已被销毁)
而Unity中却没有这样的API,往往使用==null来进行判断
那么==null到底如何来判断呢?
Part 1
public int numTest = 998; public void Print() { Debug.Log("TestScriptOfBilly.Print this.gameObject.name " + this.gameObject.name); //0 Destroy(gameObject); Debug.Log("TestScriptOfBilly this == null 1st " + (this == null).ToString()); //1 Debug.Log("TestScriptOfBilly this.numTest 1st " + numTest); //2 Debug.Log("TestScriptOfBilly this.gameObject.name 1st " + this.gameObject.name); //3 DOVirtual.DelayedCall(1.0f, () => { Debug.Log("TestScriptOfBilly DelayedCall callback this == null 2nd " + (this == null).ToString()); //4 Debug.Log("TestScriptOfBilly DelayedCall callback this.numTest 2nd " + numTest); //5 Debug.Log("TestScriptOfBilly DelayedCall callback this.gameObject.name 2nd" + this.gameObject.name);//6 }); }
结合log可以发现
Destroy之后当前帧内this(MonoBehaviour)与gameObject都未被立即销毁
1,2,3三句log可以佐证
而在延迟回调里面(Destroy之后的帧)
4,5,6三句log十分"诡异"
第4句this==null已经变为了true
第5句却仍然能访问到this.numTest的值998
第6句访问gameObject直接报错
这里大胆推测,this其实并不是null
而是由于
UnityEngine.Object
public static bool operator ==(Object x, Object y);
这里重写了运算符,把已经销毁的Object根据销毁标记在与null判定相等时返回了true
Part 2
为此我们再做一个实验
void testValid() { TestScriptOfBilly tsob = imgTest.GetComponent<TestScriptOfBilly>(); Destroy(imgTest); DOVirtual.DelayedCall(1.0f, () => { Debug.Log("DelayedCall callback tsob == null " + (tsob == null).ToString()); Debug.Log("DelayedCall callback tsob.numTest 1st " + tsob.numTest); tsob = null; Debug.Log("DelayedCall callback tsob.numTest 2nd " + tsob.numTest); }); }
可以清晰的看到
同样判空==true
1st输出了998
tsob=null赋值之后2nd未输出直接报错
因为索引null的属性报错是必然的
Part 3
再测试一下DestroyImmediate
void testValid() { TestScriptOfBilly tsob = imgTest.GetComponent<TestScriptOfBilly>(); DestroyImmediate(imgTest); Debug.Log("testValid imgTest == null " + (imgTest == null).ToString()); Debug.Log("testValid tsob == null " + (tsob == null).ToString()); Debug.Log("testValid tsob.numTest " + tsob.numTest); }
结果与预期一致 DestroyImmediate使判空可以立即生效不必等到下一帧
其余逻辑与Destroy一致
Part 4
最后终极测试一下,通过两个文件来操作
TestScriptOfBilly.cs
public void DoDestroy() { Debug.Log("TestScriptOfBilly.Print and DestroyImmediate"); DestroyImmediate(gameObject); }
TestSceneOfBilly.cs
void testValid() { TestScriptOfBilly tsob = imgTest.GetComponent<TestScriptOfBilly>(); tsob.DoDestroy(); Debug.Log("testValid imgTest == null " + (imgTest == null).ToString()); Debug.Log("testValid tsob == null " + (tsob == null).ToString()); Debug.Log("testValid tsob.numTest " + tsob.numTest); }
结果与之前一致
侧面说明Destroy并未在销毁后对参数赋值为null
无论tsob还是前面的this都是在==操作符重载里根据内部状态来判定的