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

Discussion ScriptableObject Awake(), OnEnable(), OnDisable(), OnDestroy() demystified

Discussion in 'Scripting' started by RakNet, Mar 22, 2023.

  1. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    313
    The Unity manual doesn't comprehensively explain when Awake(), OnEnable(), OnDisable(), OnDestroy() is called for Scriptable Objects. I wanted to post my findings to help others with the same confusion.

    Which functions are called, in the order they are called, for particular events.

    Creating a new scriptable object in the project, during editor time:
    Only the created scriptable object
    1. Awake()
    2. OnEnable()

    Script reload:
    All Scriptable objects in the project
    1. OnDisable()
    2. OnEnable()

    Scriptable object instantiated at runtime:
    Only the instantiated scriptable object
    1. Awake()
    2. OnEnable()

    Scriptable object instance destroyed at runtime:
    Only the destroyed scriptable object instance
    1. OnDisable()
    2. OnDestroy()

    Editor startup:
    All Scriptable objects in the project
    1. Awake()
    2. OnEnable()

    Destroying an object in the project, during editor time:
    0. No callbacks are called

    Copy/pasteable code.
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. [CreateAssetMenu(fileName = "MySO", menuName = "MySO", order = 1)]
    5. public class MySO : ScriptableObject
    6. {
    7.     private void OnDestroy()
    8.     {
    9.         Debug.Log("2. OnDestroy(): This scriptable object was destroyed at runtime.");
    10.     }
    11.    
    12.     private void OnDisable()
    13.     {
    14.         if (Application.isPlaying)
    15.         {
    16.             Debug.Log("1. OnDisable(): This scriptable object was destroyed at runtime.");
    17.         }
    18.         else
    19.         {
    20.             Debug.Log("1. OnDisable(): Scripts were reloaded due to code changes or domain reload.");
    21.         }
    22.     }
    23.    
    24.     private void OnEnable()
    25.     {
    26.         if (Application.isPlaying)
    27.         {
    28.             Debug.Log("2. OnEnable(): This scriptable object was instantiated at runtime.");
    29.         }
    30.         else
    31.         {
    32.             Debug.Log("2. OnEnable(): The editor was started OR Scripts were reloaded due to code changes or domain reload OR this scriptable object was created at editor time.");
    33.         }
    34.     }
    35.  
    36.     private void Awake()
    37.     {
    38.         if (Application.isPlaying)
    39.         {
    40.             Debug.Log("1. Awake(): This scriptable object was instantiated at runtime.");
    41.         }
    42.         else
    43.         {
    44.             Debug.Log("1. Awake(): The editor was started OR this scriptable object was created in the project at editor time.");
    45.         }
    46.     }
    47. }
    48.  
     
  2. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,295
    One small correction: it's not all scriptable objects in the project that are reloaded when rebuilding scripts, but only the ones referenced in components in the open scenes, and ones loaded in memory for other reasons.

    Editor startup:
    All scriptable objects referenced in the open scenes:
    1. Awake()
    2. OnEnable()

    Script reload:
    All scriptable objects loaded in memory:
    1. OnDisable()
    2. OnEnable()

    Change the open scene in the editor:
    All scriptable objects referenced in the opened scene and not already loaded:
    1. Awake()
    2. OnEnable()

    All scriptable objects that were loaded in memory but are not referenced in the opened scene:

    3. OnDisable()


    Another detail worth mentioning is that OnDisable and OnEnable also get called for all scriptable objects in the open scenes and loaded in memory when entering play mode - but only if Reload Domain is enabled for Enter Play Mode Settings.

    Enter play mode (Reload Domain Enabled):
    All scriptable objects loaded in memory:
    1. OnDisable()
    2. OnEnable()

    Enter play mode (Reload Domain Disabled):
    0. No callbacks are called


    A third detail is that if you select a scriptable object asset in the Project view that isn't already loaded in memory, then Awake and OnEnable are executed for the asset at this time.

    Select a scriptable object
    1. Awake()
    2. OnEnable()

    OnDisable gets called for this scriptable object after you deselect it and then change the open scene to one that doesn't contain any references to the scriptable object.

    Deselecting the scriptable object and then calling Resources.UnloadUnusedAssets also causes OnDisable to get called for it.

    (Edit: updated for accuracy)
     
    Last edited: Mar 23, 2023
    Aryazaky and RakNet like this.
  3. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,606
    I was under the impression - and partly based on my experience - it was any scriptable objects currently in memory.
     
  4. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,295
    @spiney199 Oh... you are absolutely right! I did some testing, and it seems that OnDisable, Awake and OnEnable do get called for all scriptable objects loaded in memory during script reloading, even if they are not referenced anywhere in the open scenes.

    So it looks like unloading of unused assets only happens when the open scene is changed, but not when scripts are reloaded.
     
    spiney199 likes this.