【问题标题】:Getting return value of a Coroutine in unity [duplicate]统一获取协程的返回值[重复]
【发布时间】:2020-06-13 19:55:46
【问题描述】:

我正在尝试将用户统一插入外部数据库。 我需要等到网络服务器回复错误或成功,但我无法做到......

这是我到目前为止所做的:

public class DBConnector : MonoBehaviour
{
    string BASE_URL = "https://www.XXXXXX.com/API/";

    public DBConnector()
    {
    }

    public int registerUser(User user)
    {
        int returnInt = -1;

        StartCoroutine(RegisterUser(user, returnValue =>
        {
            returnInt = returnValue;
        }
        ));

        Debug.Log(returnInt);
        return returnInt;
    }

    IEnumerator RegisterUser(User user, System.Action<int> callback = null)
    {
        Debug.Log("a register user");

        WWWForm form = new WWWForm();

        using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL + "userAPI.php", form))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
                yield return 1;
            }
            else
            {
                Debug.Log(www.downloadHandler.text);

                yield return 0;
            }
        }
    }
}

并称它为:

        Debug.Log("Before registerUser");

        conn = FindObjectOfType<DBConnector>();
        result = conn.registerUser(user);

        Debug.Log("After registerUser");

        if (result == 0)
        {
            SceneManager.LoadScene("AccountCreatedScene");
        }

RegisterUser 回调在 registerUser 方法完成后完成,因此总是返回 -1。

我是网络方面的新手,所以请帮忙.....怎么做?

谢谢

【问题讨论】:

  • 注意协程与多线程无关!

标签: c# multithreading unity3d


【解决方案1】:

您需要使用返回值实际调用callback,这就是您发送的委托没有被调用的原因。

IEnumerator RegisterUser(User user, System.Action<int> callback = null)
    {
        Debug.Log("a register user");

        WWWForm form = new WWWForm();

        using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL + "userAPI.php", form))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.Log(www.error);
                if (callback != null) { callback.Invoke(1); }
            }
            else
            {
                Debug.Log(www.downloadHandler.text);

                if (callback != null) { callback.Invoke(0); }
            }
        }
    }

您需要在您发送的委托中加载场景;这样它就会在完成后被调用。

 public void Register(User user)
    {
        StartCoroutine(RegisterUser(user, returnValue =>
        {
            if (returnValue != 0) { 
              Debug.LogError("Error"); 
              return;
            }

            // Place any logic you want post login
            SceneManager.LoadScene("AccountCreatedScene");
        }
        ));
    }

编辑:注意这是我在浏览器中编写的伪代码。

【讨论】:

    【解决方案2】:

    还有一个问题:

        int returnInt = -1;
    
        //This is working async so it won't lock your method, just start your Coroutine and go
        StartCoroutine(RegisterUser(user, returnValue =>
        {
            //Inside callback
            returnInt = returnValue;
        }
        ));
    
        //go over there where your returnInt is always -1; you should insert that log inside callback
        Debug.Log(returnInt);
    

    长话短说,您应该在该 lambda 中实现其余代码

    returnValue => { /这里/ };

    否则它会在你的协程完成之前被调用

    我会这样做:

    public void RegisterUser(User user, System.Action<int> callback)
    {
        StartCoroutine(RegisterUserCoroutine(user, callback);
    }
    
    IEnumerator RegisterUserCoroutine(User user, System.Action<int> callback = null)
    {
        Debug.Log("a register user");
    
        WWWForm form = new WWWForm();
    
        using (UnityWebRequest www = UnityWebRequest.Post(BASE_URL + "userAPI.php", form))
        {
            yield return www.SendWebRequest();
    
            if (www.isNetworkError || www.isHttpError)
            {
                //This is also bad, because default value of your callback is null, so it would throw an error
                callback(1);
    
                //This is better
                callback?.Invoke(1);
            }
            else
            {
                callback(0);
            }
        }
    }
    

    您无法将该 int 作为返回值,因为您使用的是异步函数。所以要使用该代码而不是:

    int userId = RegisterUser( user );
    DoSomethingWithUserId( userId );
    

    你应该写:

    RegisterUser( user, DoSomethingWithUserId );
    

    【讨论】:

      猜你喜欢
      • 2018-02-16
      • 1970-01-01
      • 2012-02-20
      • 2019-06-20
      • 2018-05-28
      • 2014-09-15
      • 2018-09-08
      • 2013-09-07
      • 2017-09-04
      相关资源
      最近更新 更多