2012-08-05 111 views
1

我有一個問題,幾天來一直困擾着我。NSScanner - SLOW性能 - (UITableView,NSXMLParser)

我使用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完全是空的,只有一個單獨的旋轉器旋轉。這不好。這是最後的「bug」,在我發佈這款非常出色的工作應用程序之前進行壓縮。

它在iOS模擬器上運行得很快,這並不奇怪。

在此先感謝您的任何建議。

+1

您是否確定掃描儀是瓶頸?你測量過(使用儀器)嗎?聽起來好像實際的數據傳輸可能也是一個問題。 – Till 2012-08-05 01:12:18

+0

你正在處理的數據有多大?任何低於兆字節的內容都應該快速移動。比這更大,你會看到'NSXMLParser'開始掙扎。 – 2012-08-05 01:14:32

+0

對於完全留在記憶中的東西來說,一分鐘是難以置信的緩慢。添加'NSLog'來確定那分鐘有多少時間通過網絡接收數據,或者你做了多次重複的事情。 – dasblinkenlight 2012-08-05 01:43:51

回答

3

你的算法不是很好。對於每個標籤,嘗試刪除它,即使它已被剝離。循環的每次迭代都會產生整個HTML字符串的副本,通常甚至不會剝離任何東西。如果你不使用ARC,這些副本也會一直存在,直到當前的autorelease池被彈出。你不僅浪費記憶,還會做很多不必要的工作。

測試你的方法(用Cocoa維基百科文章)需要3.5秒。

下面是該代碼的改進版本:

這會告訴掃描儀獲得的每一個字符到第一<並把它們添加到結果字符串,如果有任何。然後它會跳到下一個>,然後跳過>去掉標籤。這將重複,直到文本結束。每做一個O(n)算法,每個角色只會被觸摸。

這隻需要6.5毫秒的相同的數據。這大約快530倍。

順便說一句,那些在Mac上製作的測量。 iPhone上的確切數值當然會有所不同。

+0

斯文,你做到了!它現在在大約5-7秒內加載。巨大的進步。非常感謝你。 – Jim 2012-08-05 14:43:31

+0

非常好的答案和更快!謝謝! ;) – Lapinou 2014-03-21 10:44:23

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

0

我不知道究竟是什麼問題呢?是否花了很多時間才完成的flattenHTML方法?或者它在運行時阻止你的應用程序?

如果最後一個是你的問題,並假設你做的一切都在flattenHTML,並且確實需要很長時間才能完成。你唯一能做的就是確保你在做這個時不會阻塞你的主線程。您可以使用GCD或NSOperation來實現這一點,除了讓用戶知道您現在正在解析數據並讓他決定是否要等待或取消操作並執行其他操作之外,沒有別的辦法可以做。