Search code examples
c#unity-game-enginecoroutineienumeratorunitywebrequest

How to wait for the complete execution of a IEnumerator function in C#?


I want to get the result of a webrequest in another function but unfortunately the variable of the webrequest stays empty, because the webrequest isn't already xecuted when I call the variable. I call the OpenFile Function which calls the GetText one:

private string[] m_fileContent;

public void OpenFile(string filePath)
    {
        StartCoroutine(GetText());
        Console.Log(m_fileContent);// is empty
    }

IEnumerator GetText()
    {
        UnityWebRequest www = UnityWebRequest.Get("http://...");
        yield return www.SendWebRequest();

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            m_fileContent = www.downloadHandler.text.Split('\n');
            Debug.Log("here" + m_fileContent);//data printed ok

        }
    }

So the GetText function prints the text but in the OpenFile function the variable m_fileContent is empty.

Any ideas how to solve this?

Thank you!


Solution

  • The issue

    The line

    Console.Log(m_fileContent);
    

    is reached immediately and doesn't wait until the Coroutine finished.

    Solution

    Use an Action<string[]> and pass in a callback like e.g.

    public void OpenFile(string filePath, Action<string[]> onTextResult)
    {
        // pass in a callback that handles the result string
        StartCoroutine(GetText(onTextResult));
    }
    
    IEnumerator GetText(Action<string[]> onResult)
    {
        UnityWebRequest www = UnityWebRequest.Get("http://...");
        yield return www.SendWebRequest();
    
        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            var fileContent = www.downloadHandler.text.Split('\n');
    
            // Invoke the passed action and pass in the file content 
            onResult?.Invoke(fileContent);
        }
    }
    

    And then call it like

    // Either as lambda expression
    OpenFile("some/file/path", fileContent => {
        Console.Log(fileContent);
    });
    
    // or using a method
    OpenFile("some/file/path", OnFileResult);
    
    ...
    
    private void OnFileResult(string[] fileContent)
    {
        Console.Log(fileContent);
    }