简体   繁体   中英

stringByEvaluatingJavaScriptFromString doesn't always seem to work

I am developing an Objective C application that loads a large HTML document in to a UIWebView as the user scrolls through it. This is because the document is 20Mb and tends to crash the webview if loaded all at once. The idea is that the document is split in to chunks of HTML and as the user scrolls through it new elements are added to the document and old elements are removed.

Currently I am working on getting the Objective C application to pass data to a javascript function within the document. I have the following Objective C code:

- (BOOL)webView:(UIWebView *)webView2 
shouldStartLoadWithRequest:(NSURLRequest *)request 
navigationType:(UIWebViewNavigationType)navigationType {

NSString *url = [[request URL] absoluteString];
// Intercept custom location change, URL begins with "js-call:"
if ([url hasPrefix:@"js-call:"]) {

    // Extract the selector name from the URL
    NSArray *components = [url componentsSeparatedByString:@":"];
    NSString *function = [components objectAtIndex:1];

    // Call the given selector
    [self performSelector:NSSelectorFromString(function)];

    // Cancel the location change
    return NO;
}

// Accept this location change
return YES;

}

- (void)loadNext {
int endIndex = [self.partIndexEnd intValue];
int newEndIndex = endIndex + 9;
if (newEndIndex >= [self.parts count] - 2){
    newEndIndex = [self.parts count] - 2;
}
if (endIndex == newEndIndex){
    return; // Already at the end of the document
}

int splitLen = 300;
NSRange range = NSMakeRange(endIndex, newEndIndex - endIndex);
for (NSString *html in [self.parts subarrayWithRange:range]) {
    NSLog(@"%@", html);
    NSString *htmlToSplit = html;
    while ([htmlToSplit length] > 0) {
        NSString *curHtml;
        if ([htmlToSplit length] <= splitLen){
            curHtml = htmlToSplit;
            htmlToSplit = @"";
        }
        else {
            curHtml = [htmlToSplit substringToIndex:splitLen + 1];
            htmlToSplit = [htmlToSplit substringFromIndex:splitLen - 1];
        }

        NSString* result = [self.web stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"next('%@');", [curHtml gtm_stringByEscapingForAsciiHTML]]];

        NSLog(@"START %@ END %@", curHtml, result);
    }

}   
[self.web stringByEvaluatingJavaScriptFromString:@"next(null);"];
NSLog(@"HTML = %@ *END*", [self.web stringByEvaluatingJavaScriptFromString:@"$('body').html();"]);
}

I have the following javascript within the document:

var nextHtmlToAdd = '';
function next(html){
    var retval = '';
    try{
            if (html){
                    if (html.match(/teststring/i)){
                            alert('teststring');
                    }
                    nextHtmlToAdd = nextHtmlToAdd + html;
                    retVal = 'appended';
                    alert(html);
            } else {
                    // Finished sending HTML
                    alert('finished');
                    if (nextHtmlToAdd.match(/teststring/i)){
                            alert('encoded html contains teststring');
                    }

                    nextHtmlToAdd = $("<div/>").html(nextHtmlToAdd).text();
                    if (nextHtmlToAdd.match(/teststring/i)){
                            alert('html contains teststring');
                    }
                    alert(nextHtmlToAdd);
                    var elem = $(nextHtmlToAdd);
                    $('.endofsections').before(elem);
                    if (elem.text().match(/teststring/i)){
                            alert('element contains teststring');
                    }
                    if ($(document).text().match(/teststring/i)){
                            alert('document contains teststring');
                    }
                    nextHtmlToAdd = '';
                    retVal = 'finished';
            }
    } catch (err) {
            alert('Error: ' + err.description);
            retVal = 'error';
    }
    return retVal;
}

The Objective C code is triggered in jQuery's $(document).ready() event using the following code:

var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "js-call:loadNext");
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;

If I step through the code then what I see is the stringByEvaluatingJavaScriptFromString method being run and either returning 'appended' as a result or sometimes the returned pointer is invalid. No alerts appear within the web view and the html doesn't get appended to nextHtmlToAdd, only the first bit of HTML seems to be getting passed to the UIWebView correctly.

What I was wondering is if there is a limit on either the length of the javascript string that stringByEvaluatingJavaScriptFromString can execute or the number of times that it can be executed? Are there any alternative ways of doing this?

Thanks,

Joe

Yes, there are limits placed upon the stringByEvaluatingJavaScriptFromString method. The two you need to know about:

  • JavaScript allocations greater than 10MB are not allowed
  • JavaScript that takes longer than 10 seconds to execute is not allowed

In the former, you'll get an exception generated, but in the latter it may well fail 'silently'. Are you testing the return value of the method? If it fails it will return nil . This can be a useful way to see if your script is being terminated by the OS due to one of the reasons above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM