为什么使用HTML字符串对NSAttributedString的初始调用比后续调用长100多倍?

时间:2014-01-16 16:01:34

标签: ios objective-c cocoa-touch nsattributedstring lldb

我需要在iOS应用中显示HTML文字。我决定在NSAttributedStringinitWithData:options:documentAttributes:error:上使用内置方法。实际的解析效果非常好,但是,我似乎遇到了一个非常奇怪的错误,如果我附加了调试器,它似乎只会表现出来。

第一次调用此方法时,在运行iOS 7.0.4的iPhone 5S上运行时间不到1秒,在iPod Touch第5代上运行约1.5秒。这个怪癖也体现在模拟器上,但由于模拟器的速度很快,它显着不那么引人注目。

后续通话只需要大约10-50毫秒,这比初始通话快得多。

这似乎与输入字符串的缓存无关,因为我在“真实”应用程序中使用多个输入字符串对其进行了测试。

然而,当我在没有调试器的情况下运行程序时,它会按预期运行,大约需要10-20ms,这是我希望HTML解析所采用的。

以下是相关的代码部分:

-(void) benchmarkMe:(id)sender {
    NSData *data = [testString dataUsingEncoding:NSUTF8StringEncoding];

    NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];

    // So the complier doesn't keep complaining at me.
    __attribute__((unused))
    NSAttributedString *parsed = [[NSAttributedString alloc] initWithData:data
                                                                  options:@{
                                                                        NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                                                                        NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)
                                                                    }
                                                       documentAttributes:nil
                                                                    error:nil];

    NSTimeInterval endTime = [[NSDate date] timeIntervalSinceReferenceDate];

    NSString *message = [NSString stringWithFormat:@"Took %lf seconds.", endTime - startTime];

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Benchmark complete!"
                                                        message:message
                                                       delegate:nil
                                              cancelButtonTitle:@"Ok"
                                              otherButtonTitles:nil];
    [alertView show];
}

注意:此处提供了一个完整工作的项目来演示此错误:
https://github.com/richardjrossiii/NSAttributedStringHTMLBug

我疯了吗?这里有什么我想念的吗?当我尝试优化我的应用程序以提高性能时,1秒是非常大的时间。

我目前的解决方案是在应用程序启动时解析'虚拟'字符串,但这似乎是一个令人难以置信的hacky解决方法。

1 个答案:

答案 0 :(得分:29)

这是一个非常好的问题。事实证明(至少对我而言)无论调试器是否附加,它在第一次调用方法时总是更慢。原因如下:第一次解析HTML属性字符串时,iOS会将整个JavaScriptCore引擎和WebKit加载到内存中。观看:

我们第一次运行该方法(在解析字符串之前)只存在3个线程:

screenshot 1

解析字符串后,我们有11个主题:

screenshot 2

现在,下次我们运行该方法时,大多数与网络相关的线程仍然存在:

screenshot 3

这解释了为什么它第一次变慢而之后很快。