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

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.

using UnityEngine;

[CreateAssetMenu(fileName = "MySO", menuName = "MySO", order = 1)]
public class MySO : ScriptableObject
{
    private void OnDestroy()
    {
        Debug.Log("2. OnDestroy(): This scriptable object was destroyed at runtime.");
    }
   
    private void OnDisable()
    {
        if (Application.isPlaying)
        {
            Debug.Log("1. OnDisable(): This scriptable object was destroyed at runtime.");
        }
        else
        {
            Debug.Log("1. OnDisable(): Scripts were reloaded due to code changes or domain reload.");
        }
    }
   
    private void OnEnable()
    {
        if (Application.isPlaying)
        {
            Debug.Log("2. OnEnable(): This scriptable object was instantiated at runtime.");
        }
        else
        {
            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.");
        }
    }

    private void Awake()
    {
        if (Application.isPlaying)
        {
            Debug.Log("1. Awake(): This scriptable object was instantiated at runtime.");
        }
        else
        {
            Debug.Log("1. Awake(): The editor was started OR this scriptable object was created in the project at editor time.");
        }
    }
}
4 Likes

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)

2 Likes

I was under the impression - and partly based on my experience - it was any scriptable objects currently in memory.

@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.

1 Like