问题
I've heard that it is a bad idea to do something like this. But I am sure there is some rule of thumb which can help to get that right.
When I iterate over an NSMutableDictionary or NSMutableArray often I need to get rid of entries. Typical case: You iterate over it, and compare the entry against something. Sometimes the result is "don't need anymore" and you have to remove it. But doing so affects the index of all the rows, doesn't it?
So how could I safely iterate over it without accidently exceeding bounds or jumping over an element that hasn't been checked?
回答1:
You do so by creating a temporary array or dictionary. Either
- (Dictionary) Add the keys you want to delete later to the temporary array or
- (Array) Add the indices you want to remove later to an
NSIndexSet
or - Add the objects you want to keep to the temporary array or dictionary
Then either iterate over the temporary TODELETE-list, deleting from the main list (there might be utility methods for this), or replace the existing dictonary/array with your "temporary" one.
回答2:
If you remove an object from a mutable array while you're enumerating the same array, it will crash the app. Keep track of the objects you want to remove (you can keep their indexes in an NSIndexSet
) and use the method -(void)removeObjectsAtIndexes:(NSIndexSet *)indexes
once you are outside the enumeration loop. Alternatively, keep an NSArray
of the objects you're enumerating and use -(void)removeObjectsInArray:(NSArray *)otherArray
to delete them once you finish the loop.
Check the NSMutableArray
docs for explanations of the methods.
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html
回答3:
Or you can always resort to using explicit index in the loop and then manipulate it while removing objects. So it would look something like this
for(unsigned int i = 0; i < [myArray count]; i++) {
id obj = [myArray objectAtIndex:i];
if (condition) {
[myArray removeObject: obj];
i--;
}
}
回答4:
Given that your array does not contain any [NSNull null]
elements (which it most likely won't anyway) you could simply replace all items you need to have removed with [NSNull null]
during enumeration and once done enumerating simply call [array removeObjectIdenticalTo:[NSNull null]]
([NSNull null]
is a singleton and framework hack to allow insertion of nil into arrays).
This can be handy when memory is an issue and hence array copies not an option or when the array simply cannot be replaced by a copy.
回答5:
Here's a clever way of creating the copy, iterating, and deleting:
for (id obj in [[myArray copy] autorelease]) {
BOOL condition = ...
if (condition) {
[myArray removeObject:obj];
}
}
If it's important that you iterate in reverse for some reason:
for (id obj in [[[myArray copy] autorelease] reverseObjectEnumerator]) {
BOOL condition = ...
if (condition) {
[myArray removeObject:obj];
}
}
来源:https://stackoverflow.com/questions/2787714/safe-way-of-iterating-over-an-array-or-dictionary-and-deleting-entries