PSA: Removing objects from arrays

2011-01-01 12:04:40 UTC

  1. You create an NSMutableArray.
  2. You add the same object to it twice.
  3. You send the array one removeObjectIdenticalTo: message, passing the object you added.

What is the count of the array?

If you said 1, you’re wrong.

Worse, you might think the opposite of addObject: is removeObject: (especially if you’d never heard of the ‚ĶIdenticalTo: version), but that’s even more wrong: removeObject: finds the object(s) to remove by testing equality (sending them isEqual: messages), not simply searching for the object you passed in.* That means it may remove objects that aren’t the object you passed in, but are equal to it. So, unless you really do want to remove any objects equal to the one you have, you should prefer removeObjectIdenticalTo:.

But that still removes the object entirely from the array, regardless of how many times it’s there. Unless you really want that, you more probably want this:

NSUInteger idx = [myArray indexOfObjectIdenticalTo:obj];
[myArray removeObjectAtIndex:idx];

And even then, that will remove the object from the first place you added it in at, not the last, so if you specifically need to remove it from the last place you added it (LIFO instead of FIFO), then you need to enumerate the array backwards, counting an index down as you go, remove the object at the index upon finding the object, and finally break out of the loop.

To make that easy and avert the otherwise high likelihood of off-by-one errors in many independent implementations, here’s a category you can add to your projects. Use anywhere you need the opposite of -[NSMutableArray addObject:].

* This doesn’t matter for sets, since it dupe-checks every object coming in based on equality anyway. With a set, removing the equal object and removing the same object are the same thing, which is why NSMutableSet doesn’t have removeObjectIdenticalTo:. Not so for arrays, which is why NSMutableArray does.

2 Responses to “PSA: Removing objects from arrays”

  1. David Smith Says:

    I see your point, but I literally cannot remember ever seeing a bug caused by this. Even the “should be an implementation detail” tidbit that [NSArray array] always returns the same object has bitten me more.

  2. Questor Says:

    Thanks for this blog post… I thought I was losin\’ it or something!

    This is such a major inconsistency since it is called removeObject, not removeObjects. Personally I get the feeling that whomever coded this eons ago simply forgot to break out of the search loop once they located the object for removal.

    Don\’t know why it has never been fixed by Apple, perhaps because it might break code built on it\’s flawed design, but that would be a bad idea since it should work correctly (even if it means breaking some legacy code).

    Anyway, thanks again for the post.

Leave a Reply

Do not delete the second sentence.