Ошибка NullReference, только когда не отлаживается в Unity 3D player - PullRequest
0 голосов
/ 20 февраля 2019

Я работаю в приложении Unity 3D, где у меня есть 2 метода, которые подключаются к службе с помощью Oauth: один получает токен, а другой - выводит JSON-данные из службы на основе токена.Когда JSON готов, я изменяю текст в TextMesh.Все работает в методе запуска скрипта TextMesh.Примерно так:

void Start()
{
    string authToken = getAuthToken();
    CustomerGroups data = getCustGroups(authToken);

    TextMesh curText = (TextMesh)gameObject.GetComponent(typeof(TextMesh));
    curText.text = data.value[0].Field1+ "-" + data.value[0].Field2;
}

Как ни странно, это прекрасно работает, когда я использую «Attach to Unity» в Visual Studio и запускаю GameObject в плеере Unity, но когда я запускаю его без отладки (например, запускапара шагов) Я всегда получаю:

NullReferenceException: Object reference not set to an instance of an object
HelloWorldInteractive.getAuthToken () (at Assets/HelloWorldInteractive.cs:106)
HelloWorldInteractive.Start () (at Assets/HelloWorldInteractive.cs:15)

Фактический метод:

public string getAuthToken()
{
    string token = string.Empty;
    Dictionary<string, string> content = new Dictionary<string, string>();
    TokenClassName json = null;

    content.Add("tenant_id", "https//...");
    content.Add("grant_type", "client_credentials");
    content.Add("client_id", "xxxx");
    content.Add("client_secret", "xxxx");
    content.Add("resource", "https://...");

    UnityWebRequest www = UnityWebRequest.Post("https://login...", content);

    //Send request
    www.SendWebRequest();

    if (!www.isNetworkError)
    {
        string resultContent = www.downloadHandler.text;
        json = JsonUtility.FromJson<TokenClassName>(resultContent);

        //Return result
        token = json.access_token;
    }

    return token;
}

И снова, если я не отлаживаю его, он терпит неудачу, но когда я отлаживаю во время работыэто, это прекрасно работает.Я предполагаю, что это может быть связано с выполнением их в методе Start ... может быть, мне нужно сделать это где-нибудь еще?Мне просто нужно подготовить данные JSON, чтобы я мог изменить значение TextMesh в самом начале.

1 Ответ

0 голосов
/ 20 февраля 2019

Ваша проблема называется «состояние гонки».

Когда вы отлаживаете, вы «достаточно медленны», так что ваш UnityWebRequest очень вероятно будет иметь результат, пока вы не доберетесь до той части кода, где он необходим.

Пока не выполняется отладка:Вы не ждете до завершения веб-запроса.

поэтому www.downloadHandler.text; все равно будет иметь значение null, когда метод достигнет строки

json = JsonUtility.FromJson<TokenClassName>(resultContent);

Я не знаю, что exctaly JsonUtility.FromJson делает для null каквходное значение, но я предполагаю, что либо ошибка уже добавлена, либо она может вернуть null, поэтому следующая строка

token = json.access_token;

при попытке доступа к json со значением null выбрасываетисключение.


Вы должны использовать сопрограммы и yield, пока не получите результат (см. UnityWebRequest.Post ).

Я бы использовал метод обратного вызова, например

private IEnumerator getAuthToken(Action<string> onSuccess)
{
    string token = string.Empty;
    Dictionary<string, string> content = new Dictionary<string, string>();
    TokenClassName json = null;

    content.Add("tenant_id", "https//...");
    content.Add("grant_type", "client_credentials");
    content.Add("client_id", "xxxx");
    content.Add("client_secret", "xxxx");
    content.Add("resource", "https://...");

    UnityWebRequest www = UnityWebRequest.Post("https://login...", content);

    //Send request
    // !! wait until request finishes
    yield return www.SendWebRequest();

    if (!www.isNetworkError && !www.isHttpError)
    {
        string resultContent = www.downloadHandler.text;
        json = JsonUtility.FromJson<TokenClassName>(resultContent);

        //Return result
        token = json.access_token;

        // this should only be done on success
        // execute the callback
        onSuccess?.Invoke(token);
    }
    else
    {
        Debug.LogErrorFormat(this, "Downlaod failed with: {0} - \"{1}\"", www.responseCode, www.error);
    }
}

, и использовал бы его либо с методом обратного вызова, например

private Start()
{
    StartCoroutine(getAuthToken(OnReceivedToken));
}

privtae void OnReceivedToken(string authToken)
{
    CustomerGroups data = getCustGroups(authToken);

    TextMesh curText = (TextMesh)gameObject.GetComponent(typeof(TextMesh));
    curText.text = data.value[0].Field1+ "-" + data.value[0].Field2;     
}

, либо в качестве лямбда-выражения

* 1040.*
...