Unity3D在iOS上的WWW调用主线程问题

3
在我们正在制作的应用程序中,当应用程序暂停时,我们希望尝试远程保存用户数据。在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从未评估为true,因此整个过程就会挂起。

这是一个bug还是设计问题?如果是设计问题,那么正确的方法是什么呢?因为如果我们将其放在StartCoroutine后面,它不会正确地运行在主线程上,在暂停时,正在发生的事情会被推迟到应用程序恢复时(这完全背离了我们的初衷)。

编辑:在与一些Unity开发人员在IRC上交谈后,他们承认这实际上是代码中的一个bug,理解我需要这样做的原因,并接受需要有一种方式来同步触发WWW请求,或者在iOS的OnApplicationPause(true)流程中调用其他方法,否则(尽管可以轻松地在本地执行),在那个时间点上没有触发WWW请求的方法,唯一的选择是将它们排队直到恢复,这完全不切实际。

3个回答

1

目前Unity在某些平台(如iOS、Webplayer)上并未为www操作启动新线程,或者如果启动了新线程,也会在主线程上设置WWW.isDone。因此,以下代码:

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

不起作用。

是的,我已经添加了来自Unity iOS开发人员的响应。虽然在这种情况下这是平台的限制,但仍然必须有一种方法可以从OnApplicationPause(true)调用中触发WWW请求。目前最简单的形式是您的响应是正确的,我会标记它,但希望Unity修复错误/允许在iOS上执行此操作的方法,然后我将将其作为答案添加。 - seaders

1

您可以以任何方式启动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);
            }
        }
    }
}

0

请在Unity文档中查看此内容

使用协程,避免在Web Player上阻塞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);
}

1
你能提供一些代码吗?因为那个页面缺乏信息,正如我所说的,使用“StartCoroutine”会将任何在“yield”之后发生的事情推迟到应用程序恢复时。我需要下载像在编辑器中和 Android 上一样在主线程上进行。 - seaders
“你的答案在另一个城堡里:何时一个答案不是答案?”这篇文章讨论了在技术社区中,什么样的回答才能被认为是真正有价值的。如果一个回答只是简单地提供了一个链接或者说“我也遇到过这个问题”,那么它可能并不是一个真正的答案。相反,一个好的答案应该包含详细的解释和步骤,以帮助其他人理解和解决他们自己的问题。如果你在回答问题时能够提供这些信息,那么你的回答就会更有价值,并且对其他人来说更有用。因此,如果你在回答问题时只是提供了一个简短的回复或者链接,那么你应该考虑编辑你的回答,添加更多的信息和解释,以便其他人可以从中受益。 - user585968
这确实是一个更好的答案,但你显然没有读到问题,“因为如果我们把它放在StartCoroutine后面,它不会正确地在主线程上运行,在挂起时,发生的事情会被推迟到应用程序恢复时(这完全违背了我们尝试做的事情的目的)。” 也没有读到标题,谈论它在iOS上的情况。 - seaders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接