【问题标题】:stringByEvaluatingJavaScriptFromString doesn't always seem to workstringByEvaluatingJavaScriptFromString 似乎并不总是有效
【发布时间】:2011-11-15 08:49:57
【问题描述】:

我正在开发一个 Objective C 应用程序,当用户滚动浏览它时,它会将大型 HTML 文档加载到 UIWebView 中。这是因为该文档为 20Mb,如果一次全部加载,则往往会使 webview 崩溃。这个想法是将文档拆分为 HTML 块,当用户滚动浏览它时,会将新元素添加到文档中并删除旧元素。

目前我正在努力让 Objective C 应用程序将数据传递给文档中的 javascript 函数。我有以下目标 C 代码:

- (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();"]);
}

我在文档中有以下 javascript:

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;
}

Objective C 代码在 jQuery 的 $(document).ready() 事件中使用以下代码触发:

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

如果我单步执行代码,那么我看到的是正在运行的 stringByEvaluatingJavaScriptFromString 方法,结果要么返回“附加”,要么有时返回的指针无效。 Web 视图中没有出现任何警报,并且 html 没有附加到 nextHtmlToAdd,只有 HTML 的第一个位似乎正确地传递给了 UIWebView。

我想知道的是 stringByEvaluatingJavaScriptFromString 可以执行的javascript字符串的长度或可以执行的次数是否有限制?有没有其他方法可以做到这一点?

谢谢,

【问题讨论】:

    标签: javascript iphone objective-c ios uiwebview


    【解决方案1】:

    是的,stringByEvaluatingJavaScriptFromString 方法存在限制。你需要知道的两个:

    • 不允许分配大于 10MB 的 JavaScript
    • 执行时间超过 10 秒的 JavaScript 是不允许的

    在前者中,您会生成一个异常,但在后者中,它很可能会“静默”失败。你在测试方法的返回值吗?如果失败,它将返回nil。这是查看您的脚本是否由于上述原因之一而被操作系统终止的有用方法。

    【讨论】:

    • 感谢您的帮助。当你说超过 10Mb 时,你的意思是我可以去 [web stringByEvaluatingJavaScriptFromString: @"var x = '1234567890..... 10Mb 的数据......"]?如果是这样,那就解决了我所有的问题。
    • 不,10MB 不是指传入的字符串的大小,而是指 JavaScript 在执行过程中的内存消耗。因此,如果您的 HTML 文档大小为 20MB,并且您的 JavaScript 需要事先获取整个文档,那么您将遇到麻烦。您需要弄清楚如何延迟加载/扫描文档,而不是一次将其全部加载到内存中。
    • 啊,我明白了。这基本上就是我想要做的。您是否知道我可以传递给 stringByEvaluatingJavaScriptFromString 的字符串长度的限制是多少?我目前正在以 300 字节的块加载文档。
    • 文档在这一点上并不清楚 - 它只是指 10MB 的分配限制。我认为这意味着您正在评估的字符串也将计入该限制。
    • 我刚刚做了一个小测试,应用程序将 3k 的“a”字符附加到字符串,然后将“var a = 'the characters'”发送到 stringByEvaluatingJavaScriptFromString 它循环并不断添加更多字符.它达到大约 1560576,然后我认为它达到了 10 秒的运行时间限制。每次追加 6K 到 1849344 然后出现 malloc 错误:*** mmap(size=2777088) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to调试
    猜你喜欢
    • 2019-11-19
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多