10

I have the following code in viewDidLoad, which works properly on iOS 4.3, but it hangs on iOS 5/5.1. On iOS 5/5.1, the alert dialog is shown but can not be dismissed, the UI thread freezes, the OK button just can not be clicked.

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

Is this a bug?

Kara
  • 6,115
  • 16
  • 50
  • 57
neevek
  • 11,760
  • 8
  • 55
  • 73

4 Answers4

18

After test, I consider it as a Bug, and changing code to use

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

will solve it.

DD_
  • 7,230
  • 11
  • 38
  • 59
Toni lee
  • 485
  • 3
  • 12
  • Yes I did use the alternative as you suggested and already filed this bug to Apple. – neevek Aug 04 '12 at 08:48
  • 2
    I found if the webview call "stringByEvaluatingJavaScriptFromString" in a Blocks, would cause the same problem, it freezes, after call js-alert. – meadlai Oct 22 '12 at 07:46
  • This solution is not working when i use it withing block... javascript is not showing alert – Mihir Mehta Jun 24 '13 at 04:31
  • This worked for me as well. Does anyone know why this is caused?? Edit: I get this issue on iOS 7.1 – pav Jun 21 '14 at 21:06
  • @Toni This is worked for us on iOS8 and solved our problem. Thanks for posting this workaround! – gyurisc Nov 19 '14 at 16:00
0

Try it in - (void)viewDidAppear:(BOOL)animated instead

Autonomy
  • 402
  • 4
  • 13
-1

Why are you using GCD at all here?

Remember that in GCD there is no guarantee which thread your code will called on, regardless of queue. My guess is that your DISPATCH_QUEUE_PRIORITY_DEFAULT code happens to be running on the main thread, which is then triggering a deadlock on your dispatch_sync() call. This could be verified by examining your thread states in the debugger or Instruments.

Which gets back to my original question: what do you get by doing these convolutions instead of just calling the method directly on the main thread? You are going to block either way.

You can also change your dispatch_sync() to dispatch_async() - that should also suppress a deadlock, but should only be done if you have other concurrency needs and don't need a background thread to block.

Conrad Shultz
  • 8,748
  • 2
  • 31
  • 33
  • None of the global queues should be synchronous with respect to the main queue (which is special in that it's tied to the main thread). That's pretty much the whole point of a queue: it establishes an execution context that is asynchronous with respect to everything except itself and its target queues. – Catfish_Man Jul 21 '12 at 19:56
  • (I agree with the suggested change though) – Catfish_Man Jul 21 '12 at 19:57
  • @Catfish_Man I do not believe any promises are made as to which thread a queue will execute on. `dispatch_sync()` is notoriously confusing since, as the docs note, it will try to run on the current thread, potentially disregarding the target queue. This is a known source of deadlocks. – Conrad Shultz Jul 21 '12 at 23:09
  • The code is just for demonstration, I use it in a situation that reading from a socket in a background thread and updating the data through `stringByEvaluatingJavaScriptFromString`. Anyway, the code is supposed to work without problem. My guess is `dispatch_get_global_queue` will not likely return a queue to be executed on the main thread. and the problem is not caused by `dispatch_sync`, I changed it to `dispatch_async` with no luck. – neevek Jul 22 '12 at 01:59
  • 1
    FYI, the code **always** works on iOS 4.3, and **always** deadlocks on iOS 5.0 and iOS 5.1, so I'd rather believe this is a bug. I changed my code to use `[webView performSelectorOnMainThread:@selector(stringByEvaluatingJavaScriptFromString:) withObject:js waitUntilDone:NO]` and worked without problem on all mentioned versions of iOS. – neevek Jul 22 '12 at 02:06
  • @Neevek Very strange. I could see there having been changes to management of the underlying thread pool b/w 4.3 and 5.0 which could have revealed the issue, but I'm very surprised that `dispatch_async()` doesn't work. Recommend creating a minimal test project and filing a bug. – Conrad Shultz Jul 22 '12 at 21:37
-1

Try

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