- Home /
NullReferenceException UnityEngine.MonoBehaviour.StartCoroutine
Hello,
I want to change the Sprite of a GameObject via C# script. The picture URL I get successfully from a REST API Call. With WWW I want to create the new Sprite for the GameObject. But now I don't have no idea what i am doing wrong. I read to solve the problem by using https://docs.unity3d.com/ScriptReference/GameObject.AddComponent.html but how in detail?
This is the OnClick event script of a button:
ApiClient apiclient = new ApiClient();
string imageurl = apiclient.callSearchApiWithCSharp(realEstateType, preisText.text, zimmerText.text);
Debug.Log(imageurl);
apiclient.loadPic(imageurl);
methods to get the picture and create a sprite of it:
public void loadPic(string url)
{
WWW www = new WWW(url);
StartCoroutine(WaitForRequest(www));
}
IEnumerator WaitForRequest(WWW www)
{
yield return www;
// check for errors
if (www.error == null)
{
Debug.Log("WWW Ok!: " + www.text);
image.GetComponent<Image>().overrideSprite = Sprite.Create(www.texture, new Rect(0, 0, 438, 441), new Vector2(0.5f, 0.5f));
}
else
{
Debug.Log("WWW Error: " + www.error);
}
}
Output is:
https://s@sandboxpicis24-a.akamaihd.net/pic/orig02/L/106/539/941/106539941-0.png
NullReferenceException
UnityEngine.MonoBehaviour.StartCoroutine (IEnumerator routine) (at C:/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineMonoBehaviourBindings.gen.cs:61)
ApiClient.loadPic (System.String url) (at Assets/ApiClient.cs:89)
ObjectTypeListener.callObjectType () (at Assets/ObjectTypeListener.cs:59)
UnityEngine.Events.InvokableCall.Invoke (System.Object[] args) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:153)
UnityEngine.Events.InvokableCallList.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:634)
UnityEngine.Events.UnityEventBase.Invoke (System.Object[] parameters) (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:769)
UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:53)
UnityEngine.UI.Button.Press () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:35)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:44)
UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:52)
UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:269)
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
ControllerTrack2:ProcessTrigger(PointerEventData, GameObject) (at Assets/ControllerTrack2.cs:77)
ControllerTrack2:Process() (at Assets/ControllerTrack2.cs:49)
UnityEngine.EventSystems.EventSystem:Update()
It is pointing to StartCoroutine(WaitForRequest(www));
, this is line 89 in my code. But maybe there is a problem with WWW www = new WWW(url);
If it 's pointing to StartCoroutine(WaitForRequest(www));
, then there's some problem inside WaitForRequest
Coroutine. Do you get the debug value from Debug.Log("WWW Ok!: " + www.text);
Answer by Bunny83 · Nov 09, 2016 at 11:22 AM
Your problem is a common gotcha for Unity beginners. The "reason-chain" for this is:
Coroutines are run by the coroutine scheduler and are bound to the MonoBehaviour that has been used to start the coroutine. StartCoroutine is an instance member of MonoBehaviour.
All Components must not be created with "new". Components always need to be created with AddComponent. Components can only "live" on GameObjects.
Wrongly initialized Components (i.e. created with "new") will turn into "fake null objects".
"Fake null objects" are true C# managed classes but they are lacking the native C++ equivalent in the engine's core. They could still be used as "normal" managed classes, but nothing related to Untiy will work, Furthermore the "UnityEngine.Object" baseclass overloads the == operator and "fakes" that the object is null when it's lacking the native part. That happens when you create a Component class with new or when you Destroy such an object.
So the solution is you have to attach your "ApiClient" component to a GameObject. Unlike Components GameObjects can be created with "new". So you can simply replace
ApiClient apiclient = new ApiClient();
with
ApiClient apiclient = (new GameObject("SomeObjName")).AddComponent<ApiClient>();
This will create a new GameObject with the name "SomeObjName" and add your ApiClient component to it.
Keep in mind that the GameObject (and it's components) will now be present in the scene until you destroy it.
As alternative you could attach your ApiClient component to the same gameobject that the calling script is attached to by using:
ApiClient apiclient = gameObject.AddComponent<ApiClient>();
Every component (so MonoBehaviour as well) has the gameObject
property which can be used to access the GameObject that this component is attached to.
edit
A quick note on "Destroy". When you destroy a component, only that component will be destroyed and removed. If you call Destroy on a GameObject reference it will destroy the gameobject including all attached components (since they can't exist without GameObject) as well as all child GameObjects of the GameObject.
Answer by sh_code · Nov 09, 2016 at 11:16 AM
my psychic debugging powers are telling me that either your "GameObject image" variable is not set, or it doesn't have Image component attached to it, at the time when this line is called:
image.GetComponent<Image>().overrideSprite = Sprite.Create(www.texture, new Rect(0, 0, 438, 441), new Vector2(0.5f, 0.5f));
To check if this is the case (as well as automatically handle if it is), replace the line with
if(image != null){
Image imgComponent = image.GetComponent<Image>();
if(imgComponent == null){
Debug.Log("image object doesn't contain Image component. Adding it.");
imgComponent = (Image)image.AddComponent<Image>();
}
imgComponent.overrideSprite = Sprite.Create(www.texture, new Rect(0, 0, 438, 441), new Vector2(0.5f, 0.5f));
} else Debug.Log("image GameObject is not set to anything");
Also "thank you very much", now the word "image" looks and sounds extremely weird to me, after so many repetitions :-D Get back to tell us how the replacement code I gave you behaves.
This "could" be the reason. But i think if this is the reason for NRE then the Debug should've been called, wouldn't it?
he's got no nullchecks or debugs in his code, except "if(www.error == null)", so no, there's no Debug in his original code that would be called on any of the objects being null.
my code remedies exactly that, throws debug messages on each point along the way where objects can be null...
...except the ApiClient being null, because, being created with "new", I automatically assumed it's not $$anonymous$$onoBehavior (despite its code in the next snippet in OP suggesting it is)
I was talking about this statement Debug.Log("WWW Ok!: " + www.text);
which should be called if there's no error in www call. Acc to your suggestion, the image component might be null, that means the NRE has to occur at
image.GetComponent<Image>().overrideSprite = Sprite.Create(www.texture, new Rect(0, 0, 438, 441), new Vector2(0.5f, 0.5f));
And thus, the Debug call should have been called printing the result from www variable, that's what i'm saying.
Thank you all! The code form @Bunny83 solved the problem, but another occured. I used the code from @sh_code and that helped, too. @aditya007 is also right. :)
But I have to change another thing: my gameobjects were created in the script of loadPic, so the image were alsways null. I put them to the script where apiclient is called and it works!
Answer by sirshelley · Feb 10, 2021 at 02:46 AM
I've been using unity for 7 + years and this type of behavior sometimes still stumps me.