How to remove elements in NSMutableArray or NSMutableDictionary during enumeration?

AlexR picture AlexR · Feb 25, 2012 · Viewed 15.9k times · Source

I am using block based enumeration similar to the following code:

[[[rows objectForKey:self.company.coaTypeCode] objectForKey:statementType] 
    enumerateObjectsWithOptions:NSEnumerationConcurrent 
                     usingBlock:^(id coaItem, NSUInteger idx, BOOL *stop) { 
// block code here
}]

I would like to remove some of the objects during the enumeration process depending on the their object values.

How could I do this? I know that manipulating an mutable array or dictionary (NSMutableArray or NSMutableDictionary) during enumeration is usually not possible.

What would be the best way to implement this?

Thank you!

Answer

yuji picture yuji · Feb 25, 2012

Since you can't remove objects from an array or dictionary during enumeration, you'll have to accumulate the items you want to delete, and then delete them all after the enumeration.

If you're dealing with an array, you can just accumulate the indices.:

NSMutableIndexSet *indexesToDelete = [NSMutableIndexSet indexSet];
NSUInteger currentIndex = 0;

for (id obj in yourArray) {
    //do stuff with obj
    if (shouldBeDeleted(obj)) {
        [indexesToDelete addIndex:currentIndex];
    }
    currentIndex++;
}

[yourArray removeObjectsAtIndexes:indexesToDelete];

Since the order of the keys in an NSDictionary is undefined, for an NSMutableDictionary you'll have to accumulate keys instead:

NSMutableArray *keysToDelete = [NSMutableArray array];

for (id obj in [yourDictionary keyEnumerator]) {
    //do stuff with obj
    if (shouldBeDeleted(obj)) {
        [keysToDelete addObject:obj];
    }
}

[yourDictionary removeObjectsForKeys:keysToDelete];

It's the same thing if you're enumerating with a block. Declare the enumerator in the same scope where you declare the block and it will be retained and just work.

Also worth looking at this question from 3 years ago: Best way to remove from NSMutableArray while iterating?.