熟悉了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都是在==操作符重載里根據內部狀態來判定的