Skip to content

Attribute used to support workflows in Unity that rely heavily on object references.

License

Notifications You must be signed in to change notification settings

redbluegames/unity-notnullattribute

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Not Supported

This project is not currently supported by us. If you like it, I highly recommend buying Odin Inspector. It has a [Required] attribute and validation suite that functions similarly (but better). I was hesitant to adopt Odin at first because I wanted to use Unity's native serializer, but you can use the Inspector without the serializer.

If you'd like to continue to use this attribute, feel free to do so. Just be aware we will no longer be making contributions so you'll have to support it yourself.

Unity - NotNullAttribute

The NotNullAttribute is a custom attribute that is used to support workflows in Unity that rely heavily on GameObject and MonoBehavior references. By applying the [NotNull] attribute to public Object fields on MonoBehaviours we can get alerted when a field is not properly wired up in the Editor. This allows our code to assume the field is not null.

Screenshot of NotNullAttribute

The package comes with a drawer that renders NotNull fields in the Inspector with errors when null, and with an "*" next to their label to help identify required fields. It also includes a tool to help find NotNull violations, which can be run at launch time or as part of a build.

Example Workflow

Our workflow for UI requires each root UI screen, such as Main Menu, to be its own prefab. This root prefab controls all of its children objects, including assigning OnClick events and text, etc. We assign the children directly to the root prefab object as public members, of say a UIMainMenu.cs script.

Here is an example of the script without a NotNull attribute:

public class UI_MainMenu : MonoBehaviour
{
	public Button ContinueButton;
	
	void Awake ()
	{
		if (ContinueButton == null) {
			Debug.LogError ("ContinueButton not assigned on " + gameObject.name);
		}
		
		ContinueButton.onClick.AddListener ( ClickContinueButton );
	}

	void ClickContinueButton ()
	{
		Debug.Log ("Continue Button Clicked");
	}
}

To avoid undetected Null Pointer Errors, every object that we need to link on this Main Menu script will need to have a null error check and debug log like the one above. You can see that it would get tedious to type out this boiler plate. After a while, it would be tempting to leave off the null check and error log altogether.

Adding the NotNull gives us several advantages over the previous code:

  • Less boiler plate
    • By flagging the field as NotNull, we can remove the null check and alert, since we can be confident it will be wired up at edit time.
  • Better error handling
    • Catches null references at edit / build time, rather than having to instantiate the object to discover the bug.
    • It will also produce better error output, since we won't have to write an error log for every member.
  • Avoids referencing scene objects as string literals in code using GameObject.Find

Here is what the MainMenu script looks like with NotNull:

public class UI_MainMenu : MonoBehaviour
{
  [NotNull]
  public Button ContinueButton;
  
  void Awake ()
  {
     ContinueButton.onClick.AddListener ( ClickContinueButton );
  }
  ...
}

Installation

The easiest thing to do is to install the package from the .unitypackage file that's included in the repository.

  • In the root folder of this Github project, click the file called "NotNullAttributePackage.unitypackage".
  • Then click on View Raw to download the package.
  • In Unity, go to Assets / Import Package / Custom Package
  • Select the downloaded package
  • Install all components

You can put the folder wherever you want, but the files under the Editor folder must remain in a folder called "Editor" in order to be compiled correctly.

How to Use

Scripting

After installation you can enforce error reporting on null public fields on MonoBehaviors by using the attribute [NotNull] or [NotNullAttribute].

  [NotNull]
  public GameObject RequiredObject;

  [NotNullAttribute] // This is the same as NotNull
  public GameObject Another RequiredObject;

Also provided is a flag called IgnorePrefab for ignoring the null check on prefabs. This is valuable when a prefab is used in multiple scenes and must link to an object that is stored in each of those scenes. The null check will run for only the object you use in your scene, not its corresponding prefab in the asset database.

  [NotNull (IgnorePrefab = true)]
  public GameObject OnlyNeededInScene;

Editor

You can manually run a test of all null references using the Not Null Finder menu tool.

RedBlueTools Menu

Also note that a check for null references will be made at launch as well.

Follow the Project

Follow our progress and issues on the GitHub issues page.

FAQ

  • Why use this workflow instead of using GameObject.Find ("ObjectName") or FindComponent<> or some other way to link up cached objects as Unity suggests?
    • It's less brittle. If you link to the object through GameObject.Find (), changing the name of the object in the hierarchy or in the scene will silently break this reference.
    • It is also good for memory management. Assets that are referenced by an object will be loaded when the object is loaded, so it's easy to see what is being brought into memory when it's linked directly on a prefab or object.
    • Finally, and maybe most importantly, if somehow the reference does break, you will find out about it before the build, not at runtime.

About

Attribute used to support workflows in Unity that rely heavily on object references.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages