Last Updated: December 26, 2018
·
10.4K
· michaelmorrison

Safely remove NSMutableDictionary objects in a loop

Ever tried to remove objects from an NSMutableDictionary in a loop, only to get this exception:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFDictionary: 0x7f999b50a3e0> was mutated while being enumerated.'

Here's the code that caused this exception (dict is an NSMutableDictionary):

for (NSString *key in dict) {
  if ([key rangeOfString:@"removeMe"].length > 0) {
    [dict removeObjectForKey:key];
  }
}

So any objects with a key containing the string "removeMe" are removed from the dictionary. The problem is you're changing the dictionary as it is being enumerated, which isn't good. The trick is to base the loop on something other than the dictionary itself. How about an array of the dictionary's keys, [dict allKeys]? Let's see that same code again with this change:

for (NSString *key in [dict allKeys]) {
  if ([key rangeOfString:@"removeMe"].length > 0) {
    [dict removeObjectForKey:key];
  }
}

Now you're no longer enumerating over the dictionary itself but instead over a new array that contains the dictionary's keys. So you're not changing the enumerated object as you remove stuff from the dictionary. Problem solved!

1 Response
Add your response

Elegant fix.

One question: in this fix, would [dict allKeys] be called once for each loop? If so, then maybe more efficient to assign [dict allKeys] to a local NSArray* first?

Thanks!
-- Erik van der Neut

over 1 year ago ·