Mapping Strings to Selectors
Back in the old days of Carbon, when you wanted to handle a button press, you set up a command ID on your button, which was a simple integer, and then implemented a central command-handling function on your window that received the command ID and used a big switch statement to dispatch it to the right action.
In Cocoa, thanks to message sending and target/action, we don't have this issue anymore. Each button knows the message to send and the object to send it to, and just triggers the action directly. No gigantic switch statement.
However, we still have a similar issue in key-value observing: When you call addObserver:forKeyPath:options:context, all key-value-observing notifications go through the one bottleneck: observeValueForKeyPath:ofObject:change:context:. So, to detect which property was changed, you have to chain several if statements together and check whether the key path is the one you registered for (and check the context parameter so youre sure this is not just a KVO notification your superclass or subclass requested), and then dispatch it to a method that actually reacts to it.
It would be much nicer if Apple just called a method that already contained the name of the key-value-path, wouldnt it? E.g. if the key-path you are observing is passwordField.text, why doesnt it call observerValueOfPasswordField_TextOfObject:change:context:?
But there is a common Cocoa coding pattern that can help us with this: Mapping strings to selectors. The centerpiece of this method is the NSSelectorFromString function. So imagine you just implemented observeValueForKeyPath:ofObject:change:context: like this:
-(void) observeValueForKeyPath: (NSString*)keyPath ofObject: (id)observedObject change: (NSDictionary*)changeInfo context: (void*)context { NSString *sanitizedKeyPath = [keyPath stringByReplacingOccurrencesOfString: @"." withString: @"_"]; NSString *selName = [NSString stringWithFormat: @"observeValueOf%@OfObject:change:context:", sanitizedKeyPath]; SEL action = NSSelectorFromString(selName); if( [self respondsToSelector: action] ) { NSInvocation * inv = [NSInvocation invocationWithMethodSignature: [self methodSignatureForSelector: action]]; [inv setTarget: self]; // Argument 0 [inv setSelector: action]; // Argument 1 [inv setArgument: &observedObject; atIndex: 2]; [inv setArgument: &changeInfo; atIndex: 3]; [inv setArgument: &context; atIndex: 4]; [inv invoke] } else [super observeValueForKeyPath: keyPath ofObject: observedObject change: changeInfo context: context]; }
We build a string that includes the name of the key-path, turn it into an actual selector, and then use -performSelector:withObject:, or in more complex cases like this one NSInvocation, to actually call it on ourselves.
For cases that have no clear mapping like this, you can always maintain an NSMutableDictionary where the key is whatever string your input is and the value the selector name for your output, and then use that to translate between the two. When you make whatever call equivalent to addObserver: you have in that case, it would add an entry to the dictionary. That's probably how NSNotificationCenter does it internally.
Update:
As Peter Hosey pointed out, another good use case for this pattern is -validateMenuItem: where one could turn the menu item's action into a string and concatenate that with "validate"".