1

我有一个问题困扰了我好几天了。

我正在使用 NSXMLParser 解析 RSS 提要并将结果输入 UITableView。不幸的是,提要返回了一些我用以下方法解析出来的 HTML:

- (NSString *)flattenHTML:(NSString *)html {

NSScanner *theScanner;
NSString *text = nil;
theScanner = [NSScanner scannerWithString:html];
while ([theScanner isAtEnd] == NO) {
    [theScanner scanUpToString:@"<" intoString:NULL] ;
    [theScanner scanUpToString:@">" intoString:&text] ;
    html = [html stringByReplacingOccurrencesOfString:[NSString stringWithFormat:@"%@>", text] withString:@""];
}
html = [html stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

return html;

}

我目前在 NSXMLParser 委托方法期间调用此方法:

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{

这工作得很好但是需要将近一分钟或更长时间来解析 HTML 并将其展平为文本并填充单元格。在那无休止的一分钟内,我的 UITableView 完全是空的,只有一个旋转的微调器。这不好。这是在我发布这个原本可以很好工作的应用程序之前解决的最后一个“错误”。

它在 iOS 模拟器上运行得非常快,这不足为奇。

提前感谢您的任何建议。

4

3 回答 3

3

你的算法不是很好。对于每个标签,您都尝试将其删除,即使它已经被剥离。此外,循环的每次迭代都会生成整个 HTML 字符串的副本,通常甚至不会删除任何内容。如果您不使用 ARC,这些副本也将持续存在,直到当前的自动释放池被弹出。你不仅在浪费内存,还做了很多不必要的工作。

测试您的方法(使用 Cocoa 维基百科文章)需要 3.5 秒。

这是此代码的改进版本:

- (NSString *)flattenHTML:(NSString *)html {

    NSScanner *theScanner = [NSScanner scannerWithString:html];
    theScanner.charactersToBeSkipped = nil;

    NSMutableString *result = [NSMutableString stringWithCapacity: [html length]];

    while (![theScanner isAtEnd]) {
        NSString *part = nil;
        if ([theScanner scanUpToString:@"<" intoString: &part] && part) {
            [result appendString: part];
        }
        [theScanner scanUpToString:@">" intoString:NULL];
        [theScanner scanString: @">" intoString: NULL];
    }
    return [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

这将告诉扫描器获取每个字符到第一个字符<,并将它们附加到结果字符串(如果有)。然后它会跳到下一个>,然后也跳到去掉>标签。这将重复直到文本结束。每个字符只被触摸一次,使这成为一种O(n)算法。

对于相同的数据,这只需要 6.5 毫秒。这大约快 530 倍。

顺便说一句,这些测量是在 Mac 上进行的。iPhone 上的确切值当然会有所不同。

于 2012-08-05T12:10:06.633 回答
0

我遇到了类似的问题,我不能让它更快。而不是这个,我显示了进度条来显示解析过程是如何完成的。

ss

下面的代码是其中的一部分。

// at first, count the lines of XML file
NSError *error = nil;
NSString *xmlFileString = [NSString stringWithContentsOfURL:url
                                                   encoding:NSUTF8StringEncoding
                                                      error:&error];
_totalLines = [xmlFileString componentsSeparatedByString:@"\n"].count;

// do other things...

// delegate method when the parser find new section
- (void)parser:(NSXMLParser *)parser 
didStartElement:(NSString *)elementName 
  namespaceURI:(NSString *)namespaceURI 
 qualifiedName:(NSString *)qName 
    attributes:(NSDictionary *)attributeDict
{
    // do something ...

    // back to main thread to change app appearance
    NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
    [mainQueue addOperationWithBlock:^{

        // Here is important. Get the line number and update the progress bar.
        _progressView.progress = (CGFloat)[parser lineNumber] / (CGFloat)_totalLines;
    }];
}

我在 GitHub 中有示例项目。您可以下载并运行它。我希望我的代码对您有所帮助。

https://github.com/weed/p120727_XMLParseProgress

于 2012-08-05T06:05:46.043 回答
0

我不确定到底是什么问题?是不是这个flattenHTML方法需要很长时间才能完成?或者它在运行时阻止了您的应用程序?

如果最后一个是您的问题,并且假设您正在做所有事情flattenHTML并且确实需要很多时间才能完成。您唯一能做的就是确保在执行此操作时没有阻塞主线程。您可以使用 GCD 或 NSOperation 来实现这一点,除了让用户知道您现在正在解析数据并让他决定是否要等待或取消操作并执行其他操作之外,您无能为力。

于 2012-08-05T09:02:32.707 回答