UIWebView and JavaScript Woes

JavaScript Core is unfortunately not a public framework on iOS, leaving us at the mercy of the UIWebView class if we want to execute JavaScript in our applications. I have used JavaScript a lot recently and want to share four gotchas that I have had.

Functional code!

Turns out that JavaScript is functional, not as in working but as in a functional programming language. So when calling -[UIWebView stringByEvaluatingJavaScriptFromString:] you do not pass in for example:

return x * y;

But instead:

x * y

Yes even without the trailing ; character! The result returned from -[UIWebView stringByEvaluatingJavaScriptFromString:] will be the value of the last statement, if you add a trailing ; then the last statement will be an empty statement and you will get an empty string as a result. Took quite some time before I figured that one out.

UIWebView must be on screen to execute script

The UIWebView class will not render any content, nor execute JavaScript if it is not potentially on screen. So you must add the UIWebView to the view hierarchy even if you just have it around for executing some JavaScript in the background.

It is perfectly ok to let the web view be 0x0 pixels, or full transparency, but hidden does not seem to work either.

All access must be on the main thread

Not news since the documentation clearly says you should only work with UIKit classes on the main thread (with a few added thread safe additions in IOS 4). But this is a problem if you want to do background tasks with JavaScript, since you must call -[UIWebView stringByEvaluatingJavaScriptFromString:] from the main thread. Any long running JavaScript will block all user input and updates of the screen.

No fear though, you can make your JavaScript asynchronous. But then -[UIWebView stringByEvaluatingJavaScriptFromString:] will return before your script has finished and UIWebView do not have any obvious other way to communicate any results back to you. Obvious way that is. What you instead have to do to get asynchronious results back into the Objective-C world is by fake URL requests. Use a function like this to return results from the JavaScript world:

var returnAsyncResult = function(result, context) {
    window.location = 'result://dummy.com/' + result + '/' + context;

And then let the delegate for your UIWebView get the result as such:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
    NSString* urlString = [[request URL] absoluteString];
    if ([urlString hasPrefix:@"result:"]) {
        NSString* path = [[request URL] path];
        NSArray* pathComponents = [path pathComponents];
        NSString* result = [pathComponents objectAtIndex:1];
        NSString* context = nil;
        if ([pathComponents count] > 2) {
            context = [pathComponents objectAtIndex:2];
        [delegate javaScriptEvaluator:self
        return NO;
    } else {
        return YES;

Only String results

Turns out that -[UIWebView stringByEvaluatingJavaScriptFromString:] only returns strings as result. No problem for simple types such as said strings and numbers, but a big problem if you try to return a complex value such as an array:


This will not work, and will return a NSString of zero length. You must explicitly convert arrays to strings before returning them to the Objective-C world, easiest way would be something like this:

'[' + [1,2,3] + ']'


UIWebView is a blunt tool. Please do use http://bugreport.apple.com and file a request to make JavaScript Core a public framework. The more duplicates, the higher Apple will prioritize this issue on their todo list.

In the meantime UIWebView can be used to your bidding if treated with care.

This Post Has 8 Comments

  1. Timothy Lee

    Thanks for the post! I’m running into a problem where a Javascript method takes a long time to run and blocks the UI thread (it’s not a network request). You mentioned making the Javascript code run asynchronously…how do you do that?


  2. Tyler Young

    Hi Fredrick,

    Any suggestions on how to resize the UIWebView to 0x0 pixels? I can’t seem to get the darn thing out of full screen mode!

  3. JFA

    Hi, thanks for the post,
    I’m very beginner to Javascript but I wold like to use some code I’ve found and return results of the javascript code in objective C.

    Can this stringByEvaluatingJavaScriptFromString function read
    vars inside javascript script ?
    or only the returned value of a function ?

    can you mail me some basic xcode project with a stupid javascript script in the bundle like hello world
    just to better understand the whole setup ?

    thanks in advance

    I’m trying to build an app that takes javascript from a server and then saves it inside the app, then loads it and starts it with UIWebView
    but I’m blocked at this point with this method:
    Can you please mail me some

  4. lmnbeyond

    Great post! Thanks:)

  5. Daniel Nord


    Timothy: I think you’ve found what to do but for others looking for the solution here it is:
    function drawChartAsynchronous(data,start)
    var delay = function() { drawChart(data,start); };
    setTimeout(delay, 100);

    function drawChart(data,start)
    //Function called asynchronously

    I use this in my app Footsteps to plot a chart.


  6. David Fauthoux

    You saved hours of my life! Thank you!

Leave a Reply