Safe way of iterating over an array or dictionary and deleting entries?

倾然丶 夕夏残阳落幕 提交于 2020-01-02 20:29:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!