【问题标题】:Unity3D WWW call on main thread on iOSiOS 上主线程上的 Unity3D WWW 调用
【发布时间】:2015-06-12 09:29:03
【问题描述】:

在我们正在制作的应用程序中,我们希望在应用程序挂起时尝试​​远程用户保存数据。在 Unity 的编辑器和 Android 上,这很简单

WWW www = new WWW(_URL);
while(!www.isDone)
{
    Thread.Sleep(100);
}
Debug.Log(www.text);

(完整样本:https://github.com/SixMinute/iOSWWWGet

但在 iOS 上,www.isDone 在我们阻塞时永远不会计算为真,所以整个事情就挂了。

这是一个错误,还是设计使然?然后,如果它是设计使然,那么正确的做法是什么,因为如果我们把它放在StartCoroutine 后面,它就不会正确地放在主线程上,并且在挂起时,发生的事情会被推送到应用程序恢复时(这完全违背了我们试图做的事情的目的)。

编辑:在与 IRC 上的一些 Unity 开发人员交谈后,他们接受这实际上是代码中的一个错误,理解我需要这个的原因,并接受需要一种同步触发 WWW 请求的方法,或在 iOS 上的 OnApplicationPause(true) 流期间调用时启用此功能的其他方式,因为否则(尽管能够轻松地在本机上执行此操作)当时无法触发 WWW 请求,唯一的选择是将它们排队直到恢复,这是完全不切实际的。

【问题讨论】:

    标签: ios multithreading unity3d


    【解决方案1】:

    此时 Unity 不会为 www 操作启动新线程,至少在某些平台(iOS、网络播放器)上是这样。或者如果是这样,它会在主线程上设置 WWW.isDone。所以这段代码:

    while(!www.isDone)
         Thread.Sleep(500);  
    

    不起作用。

    【讨论】:

    • 是的,我添加了来自 Unity iOS 开发人员的响应。虽然在这种情况下这是平台的限制,但仍然有一种方法可以在挂起流程期间通过OnApplicationPause(true) 调用触发 WWW 请求。以目前最简单的形式,您的回复是正确的,我会将其标记为正确的,但希望 Unity 修复错误/允许在 iOS 上执行此操作,然后我将添加该方法作为答案。
    【解决方案2】:

    以您想要的任何方法开始您的 www 通话。在更新期间,检查 www.isDone...如果返回 true,则对其进行操作...否则通过。

    private WWW myRequest = null;
    
    void Update()
    {
        if (myRequest != null)
        {
            if (myRequest.isDone)
            {
                // process request here
    
                myRequest = null;// reset it 
            }
        }
    }
    

    如果您想支持一次触发多个 www 请求,请将您的 www 请求放入数组 List myRequests = new List() 中,然后在更新中循环遍历这些请求并检查每个请求的状态。使用时无法从 myRequests 中删除,因此请注意临时删除列表。

    private List<WWW> myRequests = new List<WWW>()
    
    void Update()
    {
        if (myRequests.Count > 0)
        {
            List<WWW> removeList = null;
    
            foreach (WWW myRequest in myRequests)
            {
                if (myRequest.isDone)
                {
                    // process request here
    
                    if (removeList == null)
                    {
                        removeList = new List<WWW>();
                    }
                    removeList.Add(myRequest);
                }
            }
            if (removeList != null)
            {
                foreach (WWW oldReq in removeList)
                {
                    myRequests.Remove(oldReq);
                }
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      Unity Documentation上查看这个

      使用协程,while 循环会在网页播放器上被阻塞:

      void SaveDate()
      {
      StartCoroutine("SaveWebData");
      }
      
      IEnumerator SaveWebData() 
      {
      // Start a download of the given URL
      WWW www = new WWW(_URL);
      
      // Wait for download to complete
      yield return www;
      
      // Completed!
      Debug.Log(www.text);
      }
      

      【讨论】:

      • 您能否提供一些代码,因为该页面非常缺乏信息,并且,正如我所说的,使用StartCoroutine 会将yield 之后发生的任何事情都推送到应用程序时简历。我需要像在编辑器和 Android 上的主线程中那样进行下载。
      • Your answer is in another castle: when is an answer not an answer?。考虑编辑您的答案以包含链接指向的文章的摘要。
      • 这是一个更好的答案好吧,但你显然没有读过这个问题,“因为如果我们把它放在StartCoroutine 后面,它在主线程上不正确,在挂起时,发生了什么当应用程序恢复时被推送(这完全违背了我们试图做的事情的目的)。”。 你没有读过标题,说它是在 iOS 上的。
      猜你喜欢
      • 2015-09-20
      • 2014-03-09
      • 2015-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多