2010-08-15 144 views
0

我正在嘗試通過其中包含大約6500個項目的NSSet進行循環。我正在使用:iPhone:快速枚舉,速度不夠快?

for (id Location in sortedArray) { 
      loc = [sortedArray objectAtIndex:i]; 
      cord = [cord stringByAppendingString:[NSString stringWithFormat:@"%f,%f ",[loc.longitude doubleValue],[loc.latitude doubleValue]]]; 
      i++; 
     } 

這工作正常,但它似乎不夠快。它得到約項目5700,我得到以下錯誤:

Program received signal: 「0」. 
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib") 

有沒有辦法循環通過數據比這更快?它需要大約20秒或更長時間,而且似乎讓用戶等待太久了!

想法?

回答

7

您使用快速枚舉設置循環,然後您忽略它。

for (id Location in sortedArray) { 
    loc = [sortedArray objectAtIndex:i]; 

第一行設置一個名爲Location環路本地變量,它在每次迭代中,點陣列中的一個項目。但是您忽略該變量並使用第二個變量loc,並且第二次從該數組中獲取該值。你應該把它改寫爲:

for (id loc in sortedArray) { 
    cord = [cord stringByAppendingString:...] 
} 

雖然我們在這,你正在構建的cord字符串的方法是堅果。您通過循環在每次迭代中創建一個新字符串。在每次迭代中使用NSMutableString並調用appendFormat:會更聰明。然後你就不會在自動釋放池中填充數千個未使用的NSString對象。因此,像這樣:

NSMutableString *cord = [NSMutableString string]; 
for (id loc in sortedArray) { 
    [cord appendFormat:...]; 
} 

的這些變化都將加快你的代碼,並顯著減少內存使用情況,並可能會消除一切是造成你所遇到的奇怪的錯誤。

+0

謝謝你,我是新手,仍然在學習,我像你說的那樣做了修改,並且顯着加快了我的代碼,允許我遍歷所有6500個項目。 – 2010-08-15 23:54:16

6

三件事:

  • 你通過一個數組,沒有一套循環。如果你不關心訂單,請循環播放。
  • 您沒有使用「快速枚舉」API。
  • + [NSString stringWithFormat:]返回一個自動釋放對象。 - [NSString stringByAppendingString:]返回另一個自動釋放對象。你使用了很多內存。
  • - [NSString stringByAppendingString:]自己創建一個副本,然後附加新的字符串。每次製作一個字符串時,複製量都會增加;你的算法是O(n )。 6500 相當大。

此外,它看起來像你使用自己的位置類。改變它返回雙打而不是(我假設)NSNumber * s。絕對不會返回NSStrings;從字符串轉換爲雙是slooooooow。或者,返回一個CLLocationCoordinate2D(一個兩個雙精度結構)以避免額外的方法調用。

讓我無恥地重寫代碼:

NSMutableString * cord = [NSMutableString stringWithCapacity:cord.count*20]; 
for (Location * loc in sortedArray) { 
    [cord appendFormat:@"%f,%f ",[loc.longitude doubleValue],[loc.latitude doubleValue]]; 
} 
+0

謝謝。我需要先排序我的設置,這就是爲什麼它是一個數組。我修復了循環以實際使用快速枚舉以及NSMutableString,它確實加快了速度,允許我遍歷所有6500值。 我正在使用我自己的Location類核心數據,它創建了雙倍的NSNumbers。不知道如何改變這一點。 ( – 2010-08-15 23:56:59

+0

讓你的函數返回一個double而不是一個NSNumber *?這不是特別困難 – 2010-08-16 22:07:45

1

不知道是什麼導致你的程序錯誤,但有兩件事情可以改善:

  1. 一旦你使用快速列舉列舉你的容器沒有必要按索引獲得項目
  2. 使用NSMutableString累加值

    NSMutableString *cord = [NSMutableString string]; 
    for (CLLocation* loc in sortedArray) { 
        [cord [email protected]"%f,%f ",[loc.longitude doubleValue],[loc.latitude doubleValue]];    
    } 
    
0

它看起來像你的應用程序被終止在這個迭代發生時佔用主線程。

您應該使用NSOperation來完成任務並異步執行它。您需要回調到主線程才能完成,但嘗試在主線程上執行此操作是一種破碎的用戶體驗 - 即使它只需要3秒鐘。

0

我只是碰到了一個有趣的(也可能鮮爲人知的)實際上是約迭代的NSSet中:

The per-iteration overhead of the fast-enumeration loop varies by the collection type — basically, whether the collection forces the code to go back for more elements after each iteration. For an array, it does not; for a set, IIRC it does. The possibility makes it hard for the compiler to reason about memory across iterations of the loop (which would otherwise be a significant advantage of fast-enumeration), and in either case there's extra overhead because of the mandatory modification checks.

...

As a rule of thumb, iterating with a block is almost always best if you're not iterating over an array.

Source

事實上,我發現,迭代使用基於塊的方法比快速列舉稍微快一點,當你正在使用NSSet。它比在集合的allObjects數組上使用快速枚舉還要快一些。