Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Statics Life Cycle [ Executed In Edit Mode ]

Discussion in 'Scripting' started by gregzo, Mar 14, 2014.

  1. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Hi to all,

    Working on editor extensions these days, having trouble with singletons behaving weirdly when exiting play mode, when investigations revealed that static variables are NOT re-initialized when exiting play mode. Is this an intended behavior?

    Demo script, with common callbacks for a refresher on their behaviour when Unity serializes / deserializes the scene:

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. [ ExecuteInEditMode ]
    4. public class StaticTest : MonoBehaviour {
    5.    
    6.     static int __int = 0;
    7.  
    8.     void CheckAndLog( string callbackName )
    9.     {
    10.         string message = callbackName + ( __int != 0 );
    11.         Debug.Log( message );
    12.     }
    13.  
    14.     void Awake()
    15.     {
    16.         CheckAndLog( "Awake: " );
    17.     }
    18.  
    19.     void OnEnable()
    20.     {
    21.         CheckAndLog( "OnEnable: " );
    22.                 if( __int == 0 )
    23.         {
    24.             __int = 1;
    25.             Debug.Log( "__int set to 1 in OnEnable" );
    26.         }
    27.     }
    28.  
    29.     void Reset()
    30.     {
    31.         CheckAndLog( "Reset: " );
    32.     }
    33.  
    34.     void Start()
    35.     {
    36.         CheckAndLog( "Start: " );
    37.     }
    38.  
    39.     void OnDisable()
    40.     {
    41.         CheckAndLog( "OnDisable: " );
    42.     }
    43.  
    44.     void OnDestroy()
    45.     {
    46.         CheckAndLog( "OnDestroy: " );
    47.     }
    48. }
    You can check the strange results in detail for yourselves. Summing up:

    Add Component
    1. Awake
    2. OnEnable //__int set to 1
    3. Reset
    4. Start

    Enter PlayMode
    1. OnDisable
    2. // statics are re-initialized before the next OnEnable call
    3. OnEnable // __int is 0, set to 1 - Danger ahead!
    4. OnDisable
    5. // non serialized fields are re-initialized here
    6. OnDestroy
    7. Awake // __int is already initialized
    8. OnEnable
    9. Start()

    Exit PlayMode
    1. OnDisable
    2. OnDestroy
    3. // non serialized fields are re-initialized here
    4. Awake // __int has not been re-initialized to 0.
    5. OnEnable
    6. Start

    After Compilation
    1. OnDisable
    //Statics are reset, serializable fields are not.
    2. OnEnable

    Conclusion, for my use case at least: always initialize statics in Awake, and zero them in OnDestroy.

    Edit: compilation resets statics, so if they are initialized in Awake, they'll be wiped clean.
    Compilation also wipes non serializable types: if you build a Dictionnary in Awake, for example, it won't survive compilation.
     
    Last edited: Mar 21, 2014
    _geo__ and alex_roboto like this.
  2. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Little interesting heads up and edit: part of the pain comes from the fact that non serialized fields are initialized at different points than statics. Updated the op to reflect this.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    I haven't ever used statics in monobehaviours... never really had a need to.

    But yes, your conclusion is in line with what unity suggests. To initialize fields (static or not) in Awake, and to reset them in OnDestroy.
     
  4. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Singletons need statics, no easy way around that…

    What bugs me most is the strange discrepancy between initialization of fields and statics, and the weird fact that statics are not re-initialized when exiting play mode ( they are when entering play mode ). It just makes editor integration that much more of a hassle…
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    If I have a singleton, I don't make it a monobehaviour.

    Mainly because there's no real way to enforce a single instance of a monobehaviour. At best you can destroy any new instances if one is created.
     
  6. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Agreed, in most cases a MonoBehaviour or ScriptableObject singleton is not the way to go - you do have to destroy any attempts at new instances in Awake() and throw a debug warning.

    But what if you want components that execute in edit mode and are singletons?

    If you have a better solution, I'd be happy to hear about it!

    Cheers,

    Gregzo
     
  7. gregzo

    gregzo

    Joined:
    Dec 17, 2011
    Posts:
    795
    Added information on what happens when Unity re-compiles after script changes.

    Summing up: writing code that cleanly executes in edit mode is quite the nightmare…
     
  8. jhorneman

    jhorneman

    Joined:
    Feb 27, 2014
    Posts:
    4
    I am really glad to hear that I'm not the only one struggling with this.

    E.g. objects are supposed to be destroyed and re-deserialized when you exit play mode. But actually they're not, not at all...