Search Unity

Can singleton public Instances only be accessed at runtime?

Discussion in 'Scripting' started by zapposh, Oct 2, 2018.

  1. zapposh

    zapposh

    Joined:
    Nov 12, 2016
    Posts:
    117
    I have a standard

    public static GameManager Instance;

    set up as a singleton during Awake();
    It contains a bunch of properties for the game.
    It is also first in the script execution order.

    Some other scripts try to access these properties during their Start() functions, along these lines

    if(GameManager.Instance.ShouldDoSomething)
    DoSomething();


    This more often than not leads to null reference exceptions.
    The properties can be accessed fine at runtime, via the same functions, outside of the Start() method.
    Same goes for a Coroutine Start() method that waits a frame before checking the properties.

    Which leads me to the question:
    Is it wrong to try and access the GameManager Instance here during Start(), even though it was created in Awake()?

    Should I just cache the GameManager instead?
    I'm trying to avoid this sort of code

    if(FindObjectOfType<GameManager>().ShouldDoSomething)
    DoSomething();
     
  2. FernandoHC

    FernandoHC

    Joined:
    Feb 6, 2018
    Posts:
    338
    No, it is not wrong to access it, but you should always have null checks when you're not sure an object has been instantiated.
    Also, if you have singleton in your project there really is no reason for you to use Find method anymore, that's pretty much the reason for the singleton.

    Use the constructor of the class to assign the instance of it for singleton.

    Code (CSharp):
    1. public class TestScript : MonoBehaviour
    2. {
    3.     static public TestScript myself;
    4.  
    5.     TestScript()
    6.     {
    7.         myself = this;
    8.     }
    9. }
    Also, check this out, just to learn a bit more about execution order:
    https://docs.unity3d.com/Manual/ExecutionOrder.html
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,332
    No, that's the correct way to do things. If you're nullreffing, there's something else going on.

    Are you by any chance instantiating this GameManager as a prefab? In that case, it won't have it's Awake run before after the first frame, which is when the other things run their Start().
     
    Joe-Censored likes this.
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    This ^^^

    The only way you can guarantee Awake has been run on your object before any other Start method is if that object is part of the scene itself.
     
  5. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,508
  6. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Also make sure your singleton object is active in the scene. If its game object starts out inactive, then Awake() won't run until you activate it.

    I usually set singleton instance variables in the constructor, as FernandoHC suggests. The constructor runs before even Awake(), and it runs even if the game object is inactive. However, you want to be really careful about doing things in the constructor of any MonoBehaviour, because Unity calls constructors implicitly to gain information on classes, which means it typically gets called at least twice even if there's only one copy of the script in your scene. So don't put anything in there that's expensive, or that will be harmful if it runs extra times.
     
  7. zapposh

    zapposh

    Joined:
    Nov 12, 2016
    Posts:
    117
    Thanks to everyone for their input.

    The GameManager gameObject is part of the scene and active, BUT, it is a prefab, which is probably what is the cause of the issue, as suggested by Baste.
    Will break the prefab instance, for further testing, and try out the constructor route too.
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,332
    If there's an instance of the prefab in the scene, it should work. I was talking about if you had some other script that instantiated that prefab during Start.