Reputation: 42139
I am trying to loop through an NSSet that has about 6500 items in it. I am using:
for (id Location in sortedArray) {
loc = [sortedArray objectAtIndex:i];
cord = [cord stringByAppendingString:[NSString stringWithFormat:@"%f,%f ",[loc.longitude doubleValue],[loc.latitude doubleValue]]];
i++;
}
This works fine, but it seems that it is NOT fast enough. It gets to about item 5700 and I get the following error:
Program received signal: “0”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
Is there a way to loop through data quicker than this? It takes about 20 seconds or more, and it seems like making the user wait this long it too much!
Ideas?
Upvotes: 0
Views: 641
Reputation: 2641
I just came across an interesting (and probably little-known) fact about iterating an 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.
Indeed I have found that iterating using the block-based methods is slightly faster than fast enumeration when you're using an NSSet. It's also slightly faster than using fast enumeration on the set's allObjects array.
Upvotes: 0
Reputation: 11805
It looks like you're app is terminated from hogging the main thread while this iteration takes place.
You should use an NSOperation
to wrap up the task and perform it asynchronously. You will need to call back to the main thread for completion, but attempting to do this work on the main thread is a broken user experience – even if it only takes 3 seconds.
Upvotes: 0
Reputation: 33592
Three things:
Additionally, it looks like you're using your own location class. Change it to return doubles instead of (I assume) NSNumber*s. Definitely do not return NSStrings; converting from string to double is slooooooow. Alternatively, return a CLLocationCoordinate2D (a struct of two doubles) to avoid an additional method call.
Let me shamelessly rewrite your code:
NSMutableString * cord = [NSMutableString stringWithCapacity:cord.count*20];
for (Location * loc in sortedArray) {
[cord appendFormat:@"%f,%f ",[loc.longitude doubleValue],[loc.latitude doubleValue]];
}
Upvotes: 5
Reputation: 84338
You set up a loop using Fast Enumeration, then you ignore it.
for (id Location in sortedArray) {
loc = [sortedArray objectAtIndex:i];
The first line sets up a loop-local variable named Location
which will, on each iteration, point to an item in the array. But you are ignoring that variable and using a second variable, loc
, and fetching the value from the array a second time. You should rewrite it as:
for (id loc in sortedArray) {
cord = [cord stringByAppendingString:...]
}
While we're at it, the way you are building the cord
string is nuts. You are creating a new string on each iteration through the loop. It would be smarter to use NSMutableString and call appendFormat:
on each iteration. Then you won't fill your autorelease pool with thousands of unused NSString objects. So something like this:
NSMutableString *cord = [NSMutableString string];
for (id loc in sortedArray) {
[cord appendFormat:...];
}
Both of those changes will speed up your code and cut down memory usage significantly, and will probably eliminate whatever was causing the weird error you encountered.
Upvotes: 6
Reputation: 170839
Not sure what cause your program error, but there's two things you can improve:
Use NSMutableString to accumulate values
NSMutableString *cord = [NSMutableString string];
for (CLLocation* loc in sortedArray) {
[cord appendFormat@"%f,%f ",[loc.longitude doubleValue],[loc.latitude doubleValue]];
}
Upvotes: 0