Is there any way to query the javascript synchronously from the main thread?
Javascript is queried from the native code using an asynchronous function with a callback parameter to handle the response:
func evaluateJavaScript(_ javaScriptString: String, completionHandler completionHandler: ((AnyObject!, NSError!) -> Void)?)
Asynchronous behavior can usually be turned synchronous by pausing the thread & controlling execution with a semaphore:
// Executing in the main thread
let sema = dispatch_semaphore_create(0)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
// Background thread
self.evaluateJavaScript("navigator.userAgent", completionHandler: { (value:AnyObject!, error: NSError!) -> Void in
if let ua = value as? String {
userAgent = ua
} else {
ERROR("ERROR There was an error retrieving the default user agent, using hardcoded value \(error)")
}
dispatch_semaphore_signal(sema)
})
}
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)
...however in this case, because the completionHandler
is always called on the main thread, the code deadlocks because the completionHandler
block will never execute (main thread was paused by the dispatch_semaphore_wait
on the last line)
Any suggestions?
EDIT
I would rather not be blocking the main thread to execute that code. But I can't decouple from the main thread without changing my APIs from synchronous to asynchronous, with a domino effect all the way up the stack (e.g. from let ua = computeUserAgent()
to computeUserAgent() {(ua: String)->Void in /*Use ua value here */}
). So I need to choose between 2 approaches that both have downsides, and I would rather pick the approach that doesn't mess up my internal APIs, especially for a task as trivial as looking up the user agent.
If you must do this...
As suggested in a comment to this answer you could run a tight loop around your semaphore wait like this.
while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With