UIWebView stringByEvaluatingJavaScriptFromString in background

假装没事ソ 提交于 2019-12-04 12:23:55

问题


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?


回答1:


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




回答2:


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...




回答3:


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.




回答4:


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



来源:https://stackoverflow.com/questions/9196620/uiwebview-stringbyevaluatingjavascriptfromstring-in-background

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!