Yielding and NullReferenceException

Hi I have two errors that appear when I run my app, the first is:
“You are trying to load data from a www stream which has not completed the download yet.
You need to yield the download or wait until isDone returns true.”
Then the second is:
“NullReferenceException: A null value was found where an object instance was required.”
The www section was originally in an IEnumerator function however it was causing too many issues and I decided it was best not to use this as it was causing too many errors that I could not fix.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Userdata : MonoBehaviour
{
    string url = "http://localhost/Wellbeing/userdata.php";
    public string[] users;
    public string[,] userArray;
    public string[] User = new string[2];
    private int nRow;
    private string[] Temp;
    private string userDataString;
    private bool value = false;
    public string[] CallDetail(string UsernameInput, string PasswordInput)
    {
        Debug.Log("hi");
        WWW userData = new WWW(url);
        string userDataString = userData.text;
        //splits the data taken from the url and splits it into a 2d array
        //splits each section of information into strings of each users data
        users = userDataString.Split(';');
        Debug.Log(users);
        //iterates through the strings and splits the into indiviual fields of data
        for (var item = 0; item <= users.Length; item++)
        {
            Temp = users[item].Split('|');
            //stores each of piece of data in the 2D array
            for (var field = 0; field <= Temp.Length; field++) 
            {
                userArray[nRow, field] = Temp[field];
            }
            nRow++;
        }
        
        //iterates through each row in the 2D array and searches for the Username and password that has been input
        for (var item = 0; item < userArray[item, 0].Length; item++)
        {
            if (userArray[item, 2] == UsernameInput && userArray[item, 1] == PasswordInput)
            {
                //stores each piece of relevant data into an array
                User[0] = userArray[item, 1];
                User[1] = userArray[item, 2];
                User[2] = userArray[item, 6];
            }
        }
        return User;
    }
}

I just don’t think it’s going to work there. You should move it back to a coroutine, so you can yield on the result.
I’m not sure about all the rest of your code, but it looks as though you’re assigning at least 1 extra string to the User array (than its size).

Not sure where your null ref error is, but maybe because you’re using the data early and it’s not ready?
If it’s something else, you should say what it is. We can’t guess it :slight_smile:

If you need to know when it’s done and/or return information, you could pass in a delegate for a callback at the end of the coroutine.

Okay I’ve done this, and sorted the issue with the adding too many strings to userArray however it now is saying "cannot implicitly convert type ‘System.Collection A2 Project Program s.IEnumerator’ to ‘string[ ]’ when I run the program, the error is being highlighted on the getcomponent in the main script where I call the IEnumerator

Right, well send a delegate (callback) as a parameter to the coroutine. Then, when it’s done you can either return the string array directly or just take the callback as an indication that the string array is ready for you (like a signal/flag of sorts).

I haven’t heard of these before could you give an example? Or maybe explain how they work?

Sure, I can try to show you an example.

// at the top of your script
using System;
void MethodThatCallsCoRoutine() {
    Action act = AfterCoroutine;
    StartCoroutine(YourRoutine(act));

}
// obviously you might have other variables, too.
IEnumerator YourRoutine(Action act) {
 //your code here..
 // at the end, when you're done
   if(act != null) act(); // this calls the method referenced by 'act'.
}
void AfterCoroutine(){
   // in here, you know that the stuff you needed is done, unless there was an error.
   // so just check that whatever you need is valid before using it, then proceed :)
}

that’s an action, which is just void delegate. In this case, no parameters are used.
An action can have parameters, too.

You can search for “System.Action C#” or “delegate c#” or “actions and delgates c#”. Stuff like that, I’m sure you’ll find some docs & examples, etc…

Hope that helps. This way your code can run and you can be notified when it’s done. Or if you go the route of passing variables, you can do that. This is assuming you can’t finish everything you need in the coroutine itself, of course.

Generally speaking, it’s good to know about actions/delegates/events. (Events are almost the same thing). :)[/code]

Ahhhh, okay thanks. Is there a way to show the user that the program is doing something and hasn’t frozen or crashed? or does it have to just be left alone to do its thing?

Can you show a message to the the user in Unity? Why, yes you can :slight_smile:

An idea is, if you think it’s going to take a little bit of time, in addition to showing a message if you want, you can break the coroutine into smaller sections with some yield return null(s).

I’m not sure, is this just for loading at the start or it happens often? If it’s not too long and rarely happens, it’s up to you…

The are several points that it would be quite useful to have a “loading screen” or “message”, as from what I understand WWW can take a few seconds