MonoBehaviour Lifecycle and Property Injection

Hi - can anyone help me understand when an injected object is available?

Say I have several GameObjects in a scene, each of which has a script like this attached to it.

public class MyObjectController : MonoBehaviour
{
    public SomeObject object;

    void Start()
    {
       // sometimes object is defined here, sometimes it's null
    }

}

And then in the inspector I’ve dragged an instance of SomeObject onto this property in the inspector for each item. Sometimes in the Start method, the injected reference to SomeObject will be null, sometimes it will be defined. In fact, some of the GameObjects will have a defined item, and others won’t.

If I use OnValidate() and run my code in the UnityIDE, then I always get an object, but on the Oculus Quest the OnValidate method never fires.

If I use Awake() the object always seems to be defined but I think this method can be called more than once.

So - which lifecycle hook should I use if I want to ensure that the reference object has been injected and exists?

Thanks

OnValidate is only called in the editor, it’s not used in builds.

Awake and Start are called only once and both work to check if the configuration is valid. The configuration in the inspector is applied before any methods are called, so in both Awake and Start you see what has been set in the editor.

If a reference you’ve assigned is null when you don’t expect it to, it could be because it has since been destroyed or you’ve got some extra instances in your scene that don’t have a reference assigned.

In Start, put a Debug.Log($"object = {object}", this); log statement (note the second argument), then play and pause the game. Now you can click on the lines in the log where object is null and Unity will highlight the game object in the hierarchy for you, so you can check if the reference has been assigned or has been destroyed (object picker will show “missing” instead of “none”). The highlighting won’t work anymore once you’ve stopped the game, so you need to do it wile it’s playing or paused.

This:

Means that this:

… did not happen for all the items, OR something else is removing them before the Start() method runs.

In Start(), print out the name of the GameObject with Debug.Log() to track down where the problem script is.

As for timing of running Awake vs Start, here is some timing diagram help:

https://docs.unity3d.com/Manual/ExecutionOrder.html

Thank you Adrian - really helpful advice.

I presume by the Editor you mean the actual Unity IDE itself? I wondered what that meant in the documentation… So this method only works when running in Unity IDE?

Your suggestion of using Debug.Log($“object = {object}”, this); was really useful. I can see that object is actually set.

I guess the problem is that although the instance EXISTS, it hasn’t necessarily yet run it’s own Start() method by the time the object with the reference runs it’s own Start()…

Also I was trying to write Debug.Log("Object " + object); which doesn’t seem to be possible. Maybe I’m too used to writing Typescript recently.

Thanks for clarifying Kurt-Dekker. The link was really useful.

Yes. OnValidate is not included in standalone builds, and should only be used for Unity editor-related functions only.
Same goes for the Reset method as well.

Thanks Vryken!