5

In an iOS app, I'm running a fairly large script on a UIWebView using stringByEvaluatingJavaScriptFromString (large in terms of the length of the javascript string). There is a brief pause after calling the javascript causing other elements on the screen to hiccup for a moment.

Placing the javascript call in a function called in the background with self performSelectorInBackground breaks the application. Is there a safe way to call run this on a background thread or otherwise prevent the interface from pausing?

4 Answers 4

3

No, Webviews and the Webkit JavaScript engine are both single-threaded and cannot be used on a background thread.

A better option is to split up your JavaScript into discrete execution blocks and pipeline them using a JavaScript timer, like this (JS code, not Obj-C):

var i = 0;
var operation = function() {

    switch (i) {
    case 0:
       //do first part of code
       break;
    case 1:
       //do second part of code
       break;
    case 2:
       //do third part of code
       break;
    etc...
    }

    //prepare to execute next block
    i++;
    if (i < TOTAL_PARTS) {
        setTimeout(operation, 0);
    }
};
operation();

That will prevent your script from blocking user interaction while it executes

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. This solves half the problem and is even a little more than is necessary. Simply calling the function which does all the work with a brief timer makes the pause much shorter. If I understand this right, once the script in the stringByEvaluatingJavaScriptFromString function executes the main thread can continue so the function called by the js timer is allowed to run independently. There is still a slight pause just from calling stringByEvaluatingJavaScriptFromString with a large string. Maybe something like this approach on the obj-c side could alleviate that.
Instead of passing the whole script as a string, you could append it as a script tag to the html for your page and then just trigger it by calling a function with stringByEvaluatingJavaScriptFromString.
That seems to have the same improvement, but still not 100%.
Did you try breaking up the script into shorter parts with a timer like I suggested originally?
3

Well, I was doing the same thing. I had to run a synchronous ajax request which was freezing my UI. So this is how I fixed it :

__block NSString *message;
    dispatch_queue_t q = dispatch_queue_create("sign up Q", NULL);
    dispatch_async(q, ^{
        NSString *function = [[NSString alloc] initWithFormat: @"signup(\'%@\',\'%@\',\'%@\')",self.email.text,self.password.text,self.name.text];

        dispatch_async(dispatch_get_main_queue(), ^{
            NSString *result = [self.webView stringByEvaluatingJavaScriptFromString:function];
            NSLog(@"%@",result);

            if ([result isEqualToString:@"1"]) {
                message = [NSString stringWithFormat:@"Welcome %@",self.name.text];
                [self.activityIndicator stopAnimating];
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
            }

            else {
                message = [NSString stringWithFormat:@"%@ is a registered user",self.name.text];
                [self.activityIndicator stopAnimating];
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
            }

            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Message" message:message delegate:self cancelButtonTitle:@"Okay" otherButtonTitles: nil];
            [alertView show];
        });
    });

The logic is simple. Go to a new thread, and from within that, dispatch to the main queue and then do the JS work and everything worked like a charm for me...

Comments

2

Anything you do with a UIWebView must be done on the main thread. It's a UI element, so this is why performSelectorInBackground breaks your app.

Comments

0

You could try putting that call into an NSOperation. Since you are working with a UI element, be sure to use the [NSOperationQueue mainQueue].

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.