NullReferenceExceptions, Singletons and Delegates

I am new to Unity and need help understanding this topic. I have read responses and it still seems difficult to grasp. Any help really dumbing this down for me would be really appreciated.

Tim

Hi Tim,

Could you be more specific with regards to what you are not sure about, for example, is it a NullReferenceException that you are uncertain of?

Yes I am uncertain of the NullReferenceException and how to instantiate a variable so this error does not get displayed in Unity. Also I just looked up two different articles pertaining to singletons, events and delegates. I did not understand what Galandil was saying when refering to the delegate must be assigned in the else code of the awake function. (Did not understand what a delegate is). Also sad to admit I am this far but what is the difference between having a variable set to Null vs false?

Hi Tim,

Ok, I’m going to move your reply here to a new topic I think as there is quite a bit to cover but we can reference back to the above responses if we need to. Give me a few minutes.


Updated Thu Dec 14 2017 18:23

Clean palette so to speak @TimB :slight_smile:

If perhaps we work through each of the items you want to understand a little better and only move on to the next when you’re ready etc, I think that will help keep the content of the topic easier to read.

Let’s start with the NullReferenceException;

A NullReferenceException exception is thrown when you try to access a member on a type whose value is null.

Let’s break that down a bit. An exception is a representation of an error that occurs at runtime. The NullReferenceException is a type of exception, specifically, relating to Null Reference.

A member refers to the data or behaviour of a class. Data would be represented as fields and properties, where-as behaviour is typically represented by methods. As an example;

public class HelloWord : MonoBehavour
{
    public void SayHello()
    {
        Debug.Log("Hello Tim!");
    }
}

In the above example, SayHello is a member of our class HelloWorld. It is a behaviour, it will output “Hello Tim!” to the console when executed.

A type, at least in our context here, refers to the class.

So, if we re-stitch that in layman’s terms, what the NullReferenceException could state is;

“An error has occurred. It occurred because we have tried to access a part of a class but the reference to that class is null, e.g. doesn’t exist.”

In most cases, a NullReferenceException will occur because you haven’t initialised the class, e.g. there isn’t an instance of it. Again, an example;

public class Car : MonoBehaviour
{
    public void Accelerate()
    {
        Debug.Log("Woohoo, I can feel the wind through my hair!");
    }
}

Above I have defined a type, it’s a reference type named Car. I have given it a single behaviour, this is represented by the method Accelerate.

Updated Thu Dec 14 2017 19:07
I should add that, whilst it only shows a single behaviour above, we are of course inheriting from MonoBehaviour in our class definition, as such, many of the MonoBehavior’s members would also be available to us.

public class Example : MonoBeaviour
{
    private Car timsCar;

    private void Start()
    {
        timsCar.Accelerate();
    }
}

Above I have created another class which will try to access a member of a Car. At the top of this class I have defined a private variable to hold a reference to the instance of our Car class. Within the Start() method, we then call the Accelerate method.

If you were to save both of these classes as scripts within Unity, and then add Example.cs as a script component to a GameObject in a scene, you would be presented with a NullReferenceException when you try to run the game.

If you created a second GameObject in the scene called TimsCar and added Car.cs as a script component to it, when you run the game you would again be presented with a NullReferenceException.

In both cases, your code within Example.cs is trying to access a type (Car) which hasn’t been initialised, it is referencing anything.

We can correct this issue in several ways;

  • we could either expose our variably publically in Example.cs, and then within the Unity editor drag our TimsCar GameObject into the now visible field in our Example script component
  • we could find our TimsCar GameObject perhaps in a Start method of our Example.cs script
  • we could even create a prefab of TimsCar, remove it from the scene, and then instantiate an instance of it all from within code

The point here is that in the above cases, our Example class now has an initialised object. Our variable timsCar is no longer null, it now references our object.

Hope this helps - any questions, let me know, if not, I’ll give the next item a go :slight_smile:


See also;

By “delegate” he is referring to the function being added to sceneLoaded

SceneManager.sceneLoaded += OnSceneLoaded;

I wouldn’t worry about the specifics of “delegates” at this level, but here’s some supporting links. It’s basically a callback function passed to the SceneManager

https://forum.unity.com/threads/how-to-use-scenemanager-onsceneloaded.399221/

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/using-delegates

Hi Rob,

Sorry for not getting back to you for so long. I have been going through the course steadily which has helped me start to understand certain aspects of my question more soundly. I simply did not know how to use the forum well enough to notice that you had actually responded to me nearly three weeks ago!

Anyways here is what I gather from NullReferenceException:

1.) A null reference exception is refering to an item that is trying to be accessed in script that has been attached to unity.
2.) The item has not be instantiated hence why we need to declare the variable in the script in the start() method, instantiate the item in the inspector by creating a public class, or actually create the item in script with some new code that I learned in the last lesson ->

projectileParent = GameObject.Find (“Projectiles”);
if(!projectileParent){
projectileParent = new GameObject(“Projectiles”);

I think I get it but I do have one more question.

The public class Example: or public class Car: In the two hypotheticals you presented to me, would those simply be the scripts themselves? Whenever I create a new script it always says the scripts name as public class “new script” : MonoBehaviour

1 Like

Hi Tim,

  1. Yes, but it could also be generated by code not attached to a GameObject in a scene, but code that is still run.

  2. Yes, but also, you may have instantiated but then later destroyed the object and thus lost the reference.

Yes, in the example I gave, the scripts would be called Example.cs and Car.cs.

When you create a new script Unity, MonoDevelop and Visual Studio will all give you a default name for the file. Depending which you use, and the way in which you create a new script, may or may not lead to the name of the class being the same. Unity requires that both the file name and class names are the same, for example;

Car.cs

public class Car : MonoBehaviour
{

}

The above would be fine, the following would not;

Ford.cs

public class Car : MonoBehaviour
{

}

Hope this helps :slight_smile:

Hi Rob,

Thanks again for taking the time to help me further my understanding of C#. When you use singletons is that so that when you call on a class you must call on the same type and further the same object within the type so that you never get a different object?

Tim

Hi Tim,

You’re very welcome.

Just to touch on some terminology. So, you have your class, and then when that class is instantiated, you have an object who’s type is of that class.

Using the car analogy again, but outside of the Unity context (as instantiation is sometimes handled differently), in the following code, I define a class called Car. It also has a default constructor, this is what will be used each time I instantiate a new instance of the Car class.

public class Car
{
    // default constructor
    public Car()
    {

    }
}

Now, when I use the above in code, I may do so like this;

public Car redCar;
public Car blueCar;

redCar = new Car();
blueCar = new Car();

In the above, we have two public variables of type Car, named differently. We then instantiate our Car which calls the default constructor in this case, and create a unique instances of it, redCar and blueCar. As such, in the above, although they were created from the same class, and, because of its simplicity are obviously very similar, they are in fact two separate objects.

With a singleton pattern you restrict the process of instantiation so that only one object of that type exists.

If we go back to Unity now, and take a look at the code for the MusicManager in the Laser Defender project;

using UnityEngine;

public class MusicPlayer : MonoBehaviour
{
    static MusicPlayer instance = null;

    /// <summary>
    /// Pre-Initialisation
    /// </summary>
    private void Awake()
    {
        if (instance != null)
        {
            Destroy(gameObject);
            Debug.Log("Duplicate MusicPlayer self-destructing!");
        }
        else
        {
            instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
    }
}

…we can see within the Awake method, we perform a check to see if we have an existing instance of our MusicPlayer object already if we do, we simply discard the one that was just created. If we do not, then we say, ok, we will use the one which was just created as our first and only instance, as the next time one is created, it will be discarded again.

If we had more than one instance of our MusicManager, we could end up with a scenario where the player sets their volume preferences in one instance, but then perhaps we try to retrieve those preferences from a different instance, which would then give us a different value.

Note, the line GameObject.DontDestroyOnLoad(gameObject) ensures that our single instance is not subsequently destroyed when the next scene loads, if it was destroyed, then each time this code ran, it would be effectively recreating the first instance over and over again.

Hope this helps :slight_smile:

Privacy & Terms