iPhone:快速枚举,不够快?

时间:2010-08-15 23:19:07

标签: iphone objective-c

我正在尝试遍历一个包含大约6500个项目的NSSet。我正在使用:

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秒或更长时间,似乎让用户等了这太久了!

想法?

5 个答案:

答案 0 :(得分: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:...];
}

这两项更改都会加快代码速度并显着降低内存使用量,并且可能会消除导致您遇到的奇怪错误的原因。

答案 1 :(得分:6)

三件事:

  • 你循环遍历一个数组,而不是一个集合。如果您不关心订单,请循环设置。
  • 您没有使用“快速枚举”API。
  • + [NSString stringWithFormat:]返回一个自动释放的对象。 - [NSString stringByAppendingString:]返回另一个自动释放的对象。你耗费了大量的内存。
  • - [NSString stringByAppendingString:]复制自身,然后附加新字符串。每次你创建一个字符串,复制量就会增加;你的算法是O(n 2 )。 6500 2 非常大。

此外,您似乎正在使用自己的位置类。将其更改为返回双精度而不是(我假设)NSNumber * s。绝对不要退回NSStrings;从字符串转换为double是slooooooow。或者,返回CLLocationCoordinate2D(两个双精度的结构)以避免额外的方法调用。

让我无耻地重写您的代码:

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

答案 2 :(得分:1)

不确定导致程序错误的原因,但有两点可以改进:

  1. 使用快速枚举枚举容器后,无需按索引获取项目
  2. 使用NSMutableString累积值

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

答案 3 :(得分:0)

看起来你的应用程序在发生迭代时终止了占用主线程。

您应该使用NSOperation来完成任务并异步执行。您将需要回调主线程以完成,但尝试在主线程上执行此操作是一种破坏的用户体验 - 即使它只需要3秒钟。

答案 4 :(得分:0)

我刚刚遇到一个关于迭代NSSet的有趣(可能鲜为人知)的事实:

  

快速枚举循环的每次迭代开销因集合类型而异 - 基本上,集合是否强制代码在每次迭代后返回更多元素。对于数组,它没有;对于一套,IIRC它确实如此。这种可能性使得编译器很难在循环的迭代中推理内存(否则这将是快速枚举的一个重要优势),并且在任何一种情况下都会因为强制修改检查而产生额外的开销。

     

...

     

根据经验,如果不在数组上进行迭代,则使用块进行迭代几乎总是最佳。

     

Source

事实上,我发现当你使用NSSet时,使用基于块的方法进行迭代比快速枚举要快一些。它也比在set的allObjects数组上使用快速枚举略快。