Implementing removeIf in Objective-C

Objective-C is so much better than C++ and C that it's not even funny. However, I still feel like it is missing some basic capabilities, especially in comparison with other dynamic languages such as Ruby and Python. The capability to pass in code blocks in Ruby to various list processing map-like methods is sorely missed. This morning I ran into a case where I needed one of those methods in particular: removeIf. I needed to remove some items from a list based some criteria. This is a pretty common occurrence, and in fact I'd needed it before but just kludged it.

So, how is it done? It turns out to be pretty simple. First design a selector:

(NSMutableArray *)removeIf:(SEL)selector target:(id)target args:(id)args;

This method (implemented as a category on NSMutableArray) needed to call selector on target for each object in its collection and remove the item from its collection if the selector returned true.

Here is an implementation:

- (NSMutableArray *)removeIf:(SEL)selector target:(id)target args:(id)args{  NSMutableArray* itemsToRemove = [NSMutableArray new];  BOOL (*fn)(id, SEL, id) =      (BOOL (*)(id, SEL, id)) objc_msgSend;  for(id item in self) {      NSMutableDictionary* newArgs = [NSMutableDictionary new];      [newArgs setDictionary:args];      [newArgs setValue:item forKey:@"item"];      BOOL shouldRemove = fn(target, selector, newArgs);      if(shouldRemove) {          [itemsToRemove addObject:item];      }      [newArgs release];  }  [self removeObjectsInArray:itemsToRemove];  [itemsToRemove release];  return self;}
The only tricky part about this implementation is that in order to handle a return type that is not an object, it is necessary to declare a custom function pointer that casts the return value appropriately. This is explained very well here.

This method could be improved by rewriting it to return a copy rather than modifying its own data.