Search Unity

Checking if GetComponent<Renderer>() is null or not

Discussion in 'Scripting' started by Rajmahal, Oct 4, 2015.

  1. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    Hi guys,

    I'm struggling with something in my code. I'm getting a null reference being thrown when I get a renderer component on an object even though I have a check for a null. Here's my code sample:

    Code (CSharp):
    1. if (!walkable) {
    2.                                 return;
    3.                         }
    4.        
    5.                         state = ts;
    6.  
    7.                         Renderer rend = GetComponent<Renderer>();
    8.  
    9.  
    10.                         if (rend == null)
    11.                             GameControlTB.instance.ShowGlobalMessage("Tile Renderer Component is Null");
    12.        
    13.                         if (!walkable) {
    14.                                 // renderer.material=matUnwalkable;  
    15.                             if (rend != null)
    16.                             {
    17.                                 rend.enabled = false;
    18.                                 rend.sharedMaterial = matUnwalkable;
    19.                             }
    20.                            
    21.                                
    22.                                 return;
    23.                         }
    Is there something special about GetComponent()<> with regards to the type of null it returns if it doesn't find the component? For some reason, the if (rend == null) is not detecting it as a null, even though no renderer component was found.
     
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    Code (csharp):
    1.  
    2. // if isn't null
    3. if(rend)
    4. {...}
    5.  
    6. // if is null
    7. if(!rend)
    8. {...}
    9.  
     
  3. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    Thanks ... I tried that but that doesn't seem to work. I still seem to run into a situation where an uncaught null reference exception is thrown from this function.
     
  4. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    987
    Does the error happen at that line "rend.enabled = false;"?
    Can you post the error? (just click on the error in the console and press ctrl c to copy it).

    Also, maybe post the rest of the code.
     
  5. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    I believe it happens due to "rend.enabled = false".

    I took those lines out and everything seemed to work fine with if (rend) and if (!rend) instead of if (rend == null).

    It's odd though because it happens very randomly. This is on an IL2CPP build on iOS ... not sure if that might be affecting things. Here's the error from Xcode when it does occur (I've never been able to get it to happen in the editor):

    **** Xcode Error:


    NullReferenceException

    at UnityEngine.Component.GetComponent[T] () [0x00000] in <filename unknown>:0

    at Tile.SetState (_TileState ts) [0x00000] in <filename unknown>:0

    at GridManager.OnHoverExit () [0x00000] in <filename unknown>:0

    at Tile.OnTouchMouseExit () [0x00000] in <filename unknown>:0

    at GameControlTB.Update () [0x00000] in <filename unknown>:0


    ***** End of Xcode Error

    I have tweaked the code slightly to the following and I haven't run into the error yet. Hopefully it fixed it though I have no idea why it would have fixed it:

    Code (CSharp):
    1. public virtual void Awake(){
    2.         thisT=transform;
    3.  
    4.         rend = GetComponent<MeshRenderer> ();
    5.  
    6.     }
    7.  
    8. public void SetState(_TileState ts){
    9.  
    10.  
    11.  
    12.  
    13.                         if (!walkable) {
    14.                                 return;
    15.                         }
    16.        
    17.                         state = ts;
    18.        
    19.                         if (!walkable) {
    20.                            
    21.                             if (rend)
    22.                             {
    23.                                 rend.enabled = false;
    24.                                 rend.sharedMaterial = matUnwalkable;
    25.                             }
    26.                            
    27.                                
    28.                         }
    29.  
    30.                         if (state == _TileState.Default && matNormal != null) {
    31.                                 if (rend) {
    32.                                         rend.sharedMaterial = matNormal; // renderer.sharedMaterial=matNormal;
    33.                                         rend.enabled = false;
    34.                                 } else {
    35.                                         Debug.Log ("Null Reference 1 caught on Tile.SetState()");
    36.                                 }
    37.                                
    38.                         } else if (state == _TileState.Selected && matNormal != null) {
    39.                                
    40.                                 if (rend) {
    41.                                         rend.enabled = true;
    42.                                         rend.sharedMaterial = matNormal;  renderer.sharedMaterial=matNormal;
    43.                                 } else {
    44.                                         Debug.Log ("Null Reference 2 caught on Tile.SetState()");
    45.                                 }
    46.                         } else if (state == _TileState.Walkable && matWalkable != null) {
    47.                                
    48.                                 if (rend) {
    49.                                         rend.enabled = true;
    50.                                         rend.sharedMaterial = matWalkable;  renderer.sharedMaterial=matWalkable;
    51.                                 } else {
    52.                                         Debug.Log ("Null Reference 3 caught on Tile.SetState()");
    53.                                 }
    54.                         } else if (state == _TileState.Hostile && matHostile != null) {
    55.                                
    56.                                 if (rend) {
    57.                                         rend.enabled = true;
    58.                                         rend.sharedMaterial = matHostile; //renderer.sharedMaterial=matHostile;
    59.                                 } else {
    60.                                         Debug.Log ("Null Reference 4 caught on Tile.SetState()");
    61.                                 }
    62.                         } else if (state == _TileState.AbilityRange && matAbilityRange != null) {
    63.                                
    64.                                 if (rend) {
    65.                                         rend.enabled = true; // Raj Recent Addition
    66.                                         rend.sharedMaterial = matAbilityRange; //renderer.sharedMaterial=matAbilityRange;
    67.                                 } else {
    68.                                         Debug.Log ("Null Reference 5 caught on Tile.SetState()");
    69.                                 }
    70.                         }
    71.  
    72.     }
    Sorry for the messy code ... been trying to do all kinds of null checks to trace down the null reference exception.
     
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Why is "Awake" a virtual function?
     
  7. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    That is peculiar ... I have absolutely no idea. That was in the original code of the template that I'm using for my game so I never noticed that. I'll try switching that out ... though oddly enough, it does seem to execute as I would expect an Awake () function to do. In the editor, the rend reference is referencing the correct mesh renderer component.
     
  8. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    If the awake function is virtual, derived implementations of this class might not use it:

    Code (CSharp):
    1.  
    2. public class Foo : MonoBehaviour {
    3.  
    4.     protected virtual void Awake()
    5.     {
    6.         Debug.Log("Foo.Awake() Called");
    7.     }
    8.  
    9. }
    10.  
    11. public class Bar : Foo {
    12.  
    13.     protected override void Awake()
    14.     {
    15.         //base.Awake(); <- commented out or unused, Foo.Awake will not be called
    16.         Debug.Log("Bar.Awake() called.");
    17.     }
    18.  
    19. }
    If I were you, I'd use properties for component links, especially if your behaviour is SUPPOSED to have that component:
    Code (CSharp):
    1.  
    2. //Handy attribute. MeshRenderer will not be able to be removed
    3. //from the gameObject this script is attached to.
    4. [RequireComponent(typeof(MeshRenderer))]
    5. public class Tile : MonoBehaviour {
    6.  
    7.     MeshRenderer _rend;
    8.     public MeshRenderer rend {
    9.         get {
    10.             return _rend ?? (_rend = GetComponent<MeshRenderer>());
    11.         }
    12.     }
    13.  
    14.     public void SetVisible(bool enabled)
    15.     {
    16.         //rend will never be null
    17.         rend.enabled = enabled;
    18.     }
    19.  
    20. }
     
    Last edited: Oct 5, 2015
    Rajmahal likes this.
  9. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    Cool ... thanks. Appreciate that. I'll make those changes.
     
  10. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    I'm also noticing this:

    Code (CSharp):
    1. rend.sharedMaterial = matNormal;  renderer.sharedMaterial=matNormal;
    2.  
    renderer is a depreceated property from unity 4.6x and previous. Did you put it there on purpose?
     
  11. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    really? Is there a different way to switch the material used on a renderer? I have several different materials (each with a different colour and transparency) and I use this code to switch the material on the meshrenderer so that the particular tile looks different.
     
  12. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    Should I use MeshRenderer instead of Renderer?
     
  13. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    renderer is what is deprecated (lower-case r) - it was just a convenience function, short for GetComponent<Renderer>(). Renderer (capital R) is still fine to use.
     
    Rajmahal likes this.
  14. BenZed

    BenZed

    Joined:
    May 29, 2014
    Posts:
    524
    Look again carefullly:

    Code (CSharp):
    1.  
    2. rend.sharedMaterial = matNormal;  renderer.sharedMaterial=matNormal;
    3.  
    4.                                                       // ^^^^^^^^ here
    I'm assuming that your 'rend' variable is MeshRenderer your tile object is using.

    I'm noticing that in several of your lines, you have renderer referenced AFTER rend, which seems like an error. You're not supposed to use the 'renderer' property anymore. It should still work, but it seems to be the case that in this code, it's throwing a null reference exception, because whatever this code is doesn't have a mesh renderer wattached to it. I'm assuming the tile meshrenderer is somewhere else in the hierarchy, and you've connected it in the inspector.

    comment out or delete any code that references rendererer
     
    Rajmahal likes this.
  15. Rajmahal

    Rajmahal

    Joined:
    Apr 20, 2011
    Posts:
    2,101
    Thanks ... I think the renderer.xxx references are mistakes when I copied and pasted here ... I had messy code in this section with lots of commented lines and I tried to clean them up. I may not have done that properly. I'll go back and adjust it based on the feedback on this thread.

    Thanks guys ... you've all been super helpful.
     
  16. atulvi

    atulvi

    Joined:
    Oct 28, 2020
    Posts:
    35
    Any Unity Component Check null or not.

    1) Create Script :
    InternalComponentExtension.cs

    Code (CSharp):
    1. public class InternalComponentExtension : MonoBehaviour
    2.  
    3.     {
    4.         [SerializeField]private static TextMeshProUGUI textMeshProUGUI;
    5.         [SerializeField]public static TextMeshProUGUI TextMeshProUGUI
    6.         {
    7.             get{
    8.                 if(textMeshProUGUI == null)
    9.                 {
    10.                     GameObject g1 = new GameObject();
    11.                     textMeshProUGUI = g1.AddComponent<TextMeshProUGUI>();
    12.                 }
    13.                 return textMeshProUGUI;
    14.             }
    15.         }
    16.        
    17.         [SerializeField]private static MeshRenderer _renderer;
    18.         [SerializeField]public static MeshRenderer Renderer
    19.         {
    20.             get{
    21.                 if(_renderer == null)
    22.                 {
    23.                     GameObject g1 = new GameObject();
    24.                     _renderer = g1.AddComponent<MeshRenderer>();
    25.                 }
    26.                 return _renderer;
    27.             }
    28.         }
    29.     }
    2) Access or Check Component
    Create Script :
    Demo.cs and add in to any GameObject.

    Code (CSharp):
    1.  
    2. public class Demo: MonoBehaviour
    3.     {
    4.      
    5.     [SerializeField]private TextMeshProUGUI cookingNote;
    6.     [SerializeField]private TextMeshProUGUI CookingNote
    7.     {
    8.         get
    9.         {
    10.             if(cookingNote == null)
    11.             {
    12.                 cookingNote = InternalComponentExtension.TextMeshProUGUI;
    13.             }
    14.             return cookingNote;
    15.         }
    16.     }
    17.    [SerializeField]private Renderer  myRenderer  ;
    18.     [SerializeField]private Renderer  MyRenderer
    19.     {
    20.         get
    21.         {
    22.             if(myRenderer  == null)
    23.             {
    24.                 myRenderer  = InternalComponentExtension.[B]Renderer  [/B];
    25.             }
    26.             return myRenderer  ;
    27.         }
    28.     }
    29. void Start()
    30. {
    31.       //Access any Renderer or TextMeshProUGUI  property.
    32.        CookingNote.text = "It is Null";
    33.        
    34.        MyRenderer.enabled = false;
    35.        MyRenderer.rendererPriority = 1;
    36. }
    37. }