【问题标题】:UIWebView stringByEvaluatingJavaScriptFromString hangs on iOS5.0/5.1 when called using GCD使用 GCD 调用 UIWebView stringByEvaluatingJavaScriptFromString 在 iOS5.0/5.1 上挂起
【发布时间】:2014-01-15 10:17:10
【问题描述】:

我在viewDidLoad 中有以下代码,它在 iOS 4.3 上正常工作,但在 iOS 5/5.1 上挂起。在 iOS 5/5.1 上,警告对话框显示但无法关闭,UI 线程冻结,无法单击 OK 按钮。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    dispatch_sync(dispatch_get_main_queue(), ^{
        [self.webview stringByEvaluatingJavaScriptFromString:@"alert('HELLO WORLD!')"];
    });
});

这是一个错误吗?

【问题讨论】:

  • 如果你有一些代码复制了这个问题,请报告给developer.apple.com/bugreporter
  • @neevek,Apple 对您记录的错误有任何回应吗?我在 iOS 7.0.3 中看到了同样的问题,所以我猜不是
  • @1800INFORMATION,没有。
  • 问题不在于警报本身吗?警报会立即返回吗?
  • @hfossli,我们无法控制警报本身,我们只是传递一个字符串,如果它没有返回,那一定是一个错误。

标签: ios objective-c uiwebview grand-central-dispatch


【解决方案1】:

经过测试,我认为这是一个Bug,并更改代码使用

[webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:js waitUntilDone:NO]

会解决的。

【讨论】:

  • 是的,我确实按照您的建议使用了替代方案,并且已经将此错误提交给 Apple。
  • 我发现如果 webview 在 Blocks 中调用 "stringByEvaluatingJavaScriptFromString" 会导致同样的问题,它会在调用 js-alert 后冻结。
  • 这个解决方案在我使用块时不起作用...javascript没有显示警报
  • 这对我也有用。有谁知道这是为什么造成的??编辑:我在 iOS 7.1 上遇到了这个问题
  • @Toni 这在 iOS8 上为我们工作并解决了我们的问题。感谢您发布此解决方法!
【解决方案2】:

改为- (void)viewDidAppear:(BOOL)animated 试试

【讨论】:

  • viewDidLoad
【解决方案3】:

你为什么在这里使用 GCD?

请记住,在 GCD 中,无论队列如何,都无法保证您的代码将调用哪个线程。我的猜测是您的DISPATCH_QUEUE_PRIORITY_DEFAULT 代码恰好在主线程上运行,这会触发您的dispatch_sync() 调用的死锁。这可以通过检查调试器或仪器中的线程状态来验证。

这又回到了我最初的问题:通过进行这些卷积而不是直接在主线程上调用方法,你会得到什么?你会阻止任何一种方式。

您还可以将dispatch_sync() 更改为dispatch_async() - 这也应该抑制死锁,但只有在您有其他并发需求并且不需要后台线程阻塞时才应该这样做。

【讨论】:

  • 没有一个全局队列应该与主队列同步(它的特殊之处在于它与主线程相关联)。这几乎就是队列的全部意义所在:它建立了一个执行上下文,该上下文对于除自身及其目标队列之外的所有内容都是异步的。
  • (我同意建议的更改)
  • @Catfish_Man 我不相信任何关于队列将在哪个线程上执行的承诺。 dispatch_sync() 是出了名的令人困惑,因为正如文档所指出的,它会尝试在当前线程上运行,可能会忽略目标队列。这是已知的死锁来源。
  • 该代码仅用于演示,我在后台线程中从套接字读取并通过stringByEvaluatingJavaScriptFromString更新数据的情况下使用它。无论如何,代码应该可以正常工作。我的猜测是dispatch_get_global_queue 不太可能返回要在主线程上执行的队列。并且问题不是由dispatch_sync引起的,我将其更改为dispatch_async没有运气。
  • 仅供参考,代码 always 适用于 iOS 4.3,而 always 在 iOS 5.0 和 iOS 5.1 上会出现死锁,所以我宁愿相信这是一个错误。我将代码更改为使用 [webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:js waitUntilDone:NO],并且在所有提到的 iOS 版本上都没有问题。
【解决方案4】:

试试

dispatch_async(dispatch_get_main_queue(), ^{
    [self.webview stringByEvaluatingJavaScriptFromString:@"alert('HELLO WORLD!')"];
});

【讨论】:

  • 它对我不起作用,performSelectorOnMainThread: 起作用。
猜你喜欢
  • 2015-07-15
  • 2012-03-29
  • 2014-08-26
  • 1970-01-01
  • 1970-01-01
  • 2014-06-23
  • 2012-01-30
  • 1970-01-01
  • 2011-04-14
相关资源
最近更新 更多