Wednesday, February 24, 2016

exceptions - NullReferenceException in Unity


Since many users are facing the NullReferenceException: Object reference not set to an instance of an object error in Unity, I thought that it would be a good idea to gather from multiple source some explanation and ways to fix this error.




Symptoms


I am getting the error below appearing in my console, what does it mean and how do I fix it?



NullReferenceException: Object reference not set to an instance of an object




Answer



Value type vs Reference type



In many programming languages, variables have what is called a "data type". The two primary data types are value types (int, float, bool, char, struct, ...) and reference type (instance of classes). While value types contains the value itself, references contains a memory address pointing to a portion of memory allocated to contain a set of values (similar to C/C++).


For example, Vector3 is a value type (a struct containing the coordinates and some functions) while components attached to your GameObject (including your custom scripts inheriting from MonoBehaviour) are reference type.


When can I have a NullReferenceException?


NullReferenceException are thrown when you try to access a reference variable that isn't referencing any object, hence it is null (memory address is pointing to 0).


Some common places a NullReferenceException will be raised:


Manipulating a GameObject / Component that has not been specified in the inspector


// t is a reference to a Transform.
public Transform t ;

private void Awake()

{
// If you do not assign something to t
// (either from the Inspector or using GetComponent), t is null!
t.Translate();
}

Retrieving a component that isn't attached to the GameObject and then, trying to manipulate it:


private void Awake ()
{
// Here, you try to get the Collider component attached to your gameobject

Collider collider = gameObject.GetComponent();

// But, if you haven't any collider attached to your gameobject,
// GetComponent won't find it and will return null, and you will get the exception.
collider.enabled = false ;
}

Accessing a GameObject that doesn't exist:


private void Start()
{

// Here, you try to get a gameobject in your scene
GameObject myGameObject = GameObject.Find("AGameObjectThatDoesntExist");

// If no object with the EXACT name "AGameObjectThatDoesntExist" exist in your scene,
// GameObject.Find will return null, and you will get the exception.
myGameObject.name = "NullReferenceException";
}

Note: Be carefull, GameObject.Find, GameObject.FindWithTag, GameObject.FindObjectOfType only return gameObjects that are enabled in the hierarchy when the function is called.


Trying to use the result of a getter that's returning null:



var fov = Camera.main.fieldOfView;
// main is null if no enabled cameras in the scene have the "MainCamera" tag.

var selection = EventSystem.current.firstSelectedGameObject;
// current is null if there's no active EventSystem in the scene.

var target = RenderTexture.active.width;
// active is null if the game is currently rendering straight to the window, not to a texture.

Accessing an element of a non-initialized array



private GameObject[] myObjects ; // Uninitialized array

private void Start()
{
for( int i = 0 ; i < myObjects.Length ; ++i )
Debug.Log( myObjects[i].name ) ;
}

Less common, but annoying if you don't know it about C# delegates:


delegate double MathAction(double num);


// Regular method that matches signature:
static double Double(double input)
{
return input * 2;
}

private void Awake()
{
MathAction ma ;


// Because you haven't "assigned" any method to the delegate,
// you will have a NullReferenceException
ma(1) ;

ma = Double ;

// Here, the delegate "contains" the Double method and
// won't throw an exception
ma(1) ;

}

How to fix ?


If you have understood the previous paragraphes, you know how to fix the error: make sure your variable is referencing (pointing to) an instance of a class (or containing at least one function for delegates).


Easier said than done? Yes, indeed. Here are some tips to avoid and identify the problem.


The "dirty" way : The try & catch method :


Collider collider = gameObject.GetComponent();

try
{

collider.enabled = false ;
}
catch (System.NullReferenceException exception) {
Debug.LogError("Oops, there is no collider attached", this) ;
}

The "cleaner" way (IMHO) : The check


Collider collider = gameObject.GetComponent();

if(collider != null)

{
// You can safely manipulate the collider here
collider.enabled = false;
}
else
{
Debug.LogError("Oops, there is no collider attached", this) ;
}




When facing an error you can't solve, it's always a good idea to find the cause of the problem. If you are "lazy" (or if the problem can be solved easily), use Debug.Log to show on the console information which will help you identify what could cause the problem. A more complex way is to use the Breakpoints and the Debugger of your IDE.


Using Debug.Log is quite useful to determine which function is called first for example. Especially if you have a function responsible for initializing fields. But don't forget to remove those Debug.Log to avoid cluttering your console (and for performance reasons).


Another advice, don't hesitate to "cut" your function calls and add Debug.Log to make some checks.


Instead of :


 GameObject.Find("MyObject").GetComponent().value = "foo" ;

Do this to check if every references are set :


GameObject myObject = GameObject.Find("MyObject") ;

Debug.Log( myObject ) ;


MySuperComponent superComponent = myObject.GetComponent() ;

Debug.Log( superComponent ) ;

superComponent.value = "foo" ;

Even better :


GameObject myObject = GameObject.Find("MyObject") ;


if( myObject != null )
{
MySuperComponent superComponent = myObject.GetComponent() ;
if( superComponent != null )
{
superComponent.value = "foo" ;
}
else
{
Debug.Log("No SuperComponent found onMyObject!");

}
}
else
{
Debug.Log("Can't find MyObject!", this ) ;
}

Sources:



  1. http://answers.unity3d.com/questions/47830/what-is-a-null-reference-exception-in-unity.html


  2. https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it/218510#218510

  3. https://support.unity3d.com/hc/en-us/articles/206369473-NullReferenceException

  4. https://unity3d.com/fr/learn/tutorials/topics/scripting/data-types


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...