Question about Singleton that gives NullRefException

Hi,

Just started to learn about Singletons + persistent objects among Scenes and trying to learn scripting in Csharp. I have a few general questions regarding the lifetime of a gameObject in Application runtime.

I have a singleton object where in its Awake() method I reference another object.
This eventually gives a nullrefexception when another scene is loaded. Becuase, probably that object being referenced previously is already gets destroyed upon loading next scene.

My questions are,

  1. If you would use a persistent singleton with DontDestroyOnLoad(gameObject); how would you reference to other objects inside it? I mean I learned that referencing other objects/scripts or using GetComponent() etc is better setup and done within Awake and Start methods for performance reasons.
    So how do you solve above problem when other(referenced) object is set to be destroyed? Do you use Events and Delegates and inform the singleton accordingly to execute methods in it instead of referencing other objects in it?

  2. As long as an gameObject is not being destroyed and stays persistent, the Awake() and Start() methods are called just once within Application’s lifetime. Right?

  3. What is the difference between,

private SomeClass someClass;
.....
someClass = FindObjectOfType<SomeClass>();

and

SomeClass someClass = new SomeClass();

What are different use cases for these?

When you add “new” keyword and instantiate an object, does it create a new/specific instance of that object every time and allocates memory accordingly?
I feel a bit confused about instantiating objects/members of classes and variables of classes.

Any help and explanation is much appreciated.
Thank you,

I think your first step should be to clarify how exactly you want to use your Singleton. Is it:

  1. A single object, that persists through the lifetime of your app, constantly? If so, then it can’t reliably hold references to objects in scenes.
  2. An object per-scene, that lives and dies with that scene? This will allow you to hold references to objects in that scene, but data won’t persist. You’ll want your code to fail gracefully if this singleton doesn’t exist at a given moment.

If you need both, you probably want two different singletons (a GameManager and a SceneManager, maybe).

Correct. I think what you’re seeing is that you have a new object being loaded with the scene, and that’s the Awake/Start that’s running on scene load.

Let’s stop right there - you can’t use “new” for MonoBehaviours. You want it to either load a known prefab (through an Addressables kind or Resources name, for example) to assign from, or you want it to spawn an object and create a new one from scratch. But only do those things if the singleton doesn’t already exist.

Generally, you want something like this property:

public static SomeClass Instance {
  get {
    if (_instance == null) {
      GameObject newGO = new GameObject("SomeClass");
      DontDestroyOnLoad(newGO);
      _instance = newGO.AddComponent<SomeClass>();
    }
    return _instance;
  }
}

private static SomeClass _instance;

So it’ll create an instance the first time you access it, but from then on, the object will persist and that’ll be the one that gets used.

1 Like

Hi StarManta,

Thank you for the reply!
Actually I didn’t intend to use “new” keyword for my Singleton class. I just don’t get when do you use it or not. I mean what is the sole purpose of using “new” keyword in layman terms? :roll_eyes:

On the other hand, I was trying to implement my singleton within its Awake() method. Is this acceptable or should I do it like in your example and define it as a property? Are there any drawbacks when I do so in Awake()?

BTW, I have seen a small website of yours(where you answer some newbie FAQs) while searching for some answers on the forum and it seems quite useful.

Thank you!

In C# and similar programming languages, the new keyword is how you instantiate an object.
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator

If you have a plain C# class:

public class MyClass
{
  public int myInt;
  public string myString;
  public bool myBool;
}

You instantiate it like so:

MyClass myClass = new MyClass();

The reason Unity warns you if you instantiate MonoBehaviours or ScriptableObjects like this is because it expects you to use the Object.Instantiate method instead, which allows it to properly setup the object & its lifecycle hooks.

A MonoBehaviour cannot exist without being attached to a GameObject, so doing something like this…

Rigidbody rb = new Rigidbody();

…Means you would have a Rigidbody that doesn’t exist on any GameObject in the scene.

It’s worth mentioning that the Object.Instantiate method is purely a Unity-specific thing for MonoBehaviours & ScriptableObjects. In a plain C# project, you instantiate everything with the new keyword.

The new keyword does have a few other uses in C# as well, but that’s beyond the point here. At it’s core, it’s used to instantiate objects.

1 Like

Thank you for further explanation,
But the thing I am actually asking about is,

When would you instantiate a class using “new” keyword instead of referencing it?
I mean with my question above,

let’s say I have a Car class.
I can use below code to reference it like,

private Car car,

Start(){
car = FindObjectOfType<Car>();

Update(){
car.doSomeThingsWithThis;
}

}

and then do whatever I do with that.

So why would you instantiate it using “new” keyword instead of directly referencing it?

Is it because that the way I’m referencing above and doing further things affect the whole Car class AND when I need to have a specific car (Toyota, Mercedes that inherits Car class) then instantiate it using “new” and do further specific things with “that” particular instance instead of affecting whole Car class?

Is this the distinction between referencing and instantiating(using “new”) a class?

Thank you,

When the thing already exists, you reference it. There’s virtually no scenario where you can reference it but should create a new thing instead.

When you’re creating a new thing, and it’s a Unity object, you instantiate it (using Instantiate, for example).

When you’re creating a new thing and it’s not a UnityEngine.Object (say, a Vector3), you use new.

If you’re not sure whether a thing exists, you can try to find it, and then check to see if the result is null - if it’s null, you can move on to creating it.

2 Likes

Like StarManta said, if an instance already exists, you can just reference that instance.
Instantiating an object is for when you want to create an instance that doesn’t already exist.

1 Like