Search Unity

redux: Destroying self and all children

Discussion in 'Scripting' started by ricarious, Jun 13, 2019.

  1. ricarious

    ricarious

    Joined:
    Nov 1, 2017
    Posts:
    21
    I have read numerous opinions on the proper way to recursively delete a GameObject and all its children.

    1. The most common answer is:
    Code (CSharp):
    1. foreach( Transform t in transform) {
    2.   Destroy(t.gameObject);    // Destroy() destroys the gameobject and its subgraph
    3. }
    4. Destroy(transform.gameObject);
    The foreach seems unsafe since it modifies the loop constraints during execution. My testing on this has been inconclusive (some cases it executes fine, while some cases the loop terminates too early.... suggesting that it's unsafe, i.e., just because something works, does not mean it's safe).

    2. Another common suggestion is to first gather all of the go's, and then delete them (to avoid screwing up the loop execution):
    Code (CSharp):
    1. Transform[] allChildren = GetComponentsInChildren<Transform>();  // collect entire sub-graph into array
    2. foreach(Transform t in allChildren) {
    3.   Destroy(t.gameObject);
    4. }
    3. Another common suggestion is to use a backwards for loop (to avoid screwing the array). This assumes that Transform stores children in an array.
    Code (CSharp):
    1. for(int = transform.childCount; i > 0; i--) {
    2.   Destroy(t.gameObject);
    3. }
    4. Destroy(transform.gameObject);
    4. The fourth approach would be to write a recursive traversal starting at the node, adding self and each child to the delete list, and then delete the list after recursion completes.

    So, what is the best practice for a Unity destroy loop?
     
  2. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    What? you just destroy the parent, all child objects are destroyed too.

    edit: also, "screwing up the array" isn't a thing with the Destroy function as it takes action only before the next update, you have DestroyImmediate but it's something you should use unless you absolutely must destroy it NOW.
     
    Vryken likes this.
  3. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,445
    As SparrowsNest says, you're over-thinking it. Destroy the parent. It doesn't orphan the children.

    On this suggestion in particular, Destroy() just marks objects for destruction at the end of the frame. You don't need to do tricky reverse-iteration on the hierarchy, unlike some C# collections, because you're not modifying the structure during the loop. You're just marking things for destruction later.
     
    ricarious and SparrowGS like this.
  4. ricarious

    ricarious

    Joined:
    Nov 1, 2017
    Posts:
    21
    Thanks for quick reply. Sorry, but I really meant to ask about deleting the children of a node (not self).

    My concern was that the foreach child loop is self-modifying (i.e. calling Destroy() would modify transform's internal child list):
    foreach( Transform t in transform) { Destroy(t.gameObject); }


    So, I added OnDestroy() on all the children to test, and noted that OnDestroy() was called for every node in the sub-graph (as expected) after the foreach loop was done, and it was during the same frame.

    I believe this confirms your point that Destroy() is delayed and the loop is safe. Thanks.