Home > Articles > Programming > General Programming/Other Languages

  • Print
  • + Share This
From the author of Targets and Actions

Targets and Actions

The first pattern that you are likely to encounter with Cocoa is the target-action pattern. This is used all through AppKit, but it can also be useful in your own code. You can think of this as a very simple version of the delegation pattern, where the delegate only implements one method. The main difference is that this method does not have a fixed name.

Action methods take one argument[md]the sender[md]and return nothing. Because the sender is the argument, they can access any properties of the sender. When you connect an object's action up to another object in Interface Builder, you are setting two properties in the sender: the target and the selector.

Some objects use a generalized form of this for callbacks. You provide the object and selector, and that method will be called later. This is very easy to do. Every Objective-C method is looked up when it is called from the selector and the receiver. You can construct selectors from strings at runtime with NSSelectorFromString() or at compile time with @selector().

One similar pattern that is not common in Cocoa but is in other Objective-C code is the call-by-prefix pattern. This is used by KVC. For example, when you try to set the "fish" property in an object, KVC will try to call the -setFish: method.

It's very useful when you want to define a pattern for callback methods. One place where I've used this pattern is in an XML parser. Each element is parsed by a different class, and when it is finished then it needs to provide the parsed result to the parent element. This is done by calling a method in the parent that starts with handle and ends with the name of the element. For example, you'd call the -handleli method to pass a parsed HTML list item to the handler for the list.

This is very easy to implement. You just need to construct the selector, test whether it's implemented, and then call the method if it is, like this:

SEL selector = NSSelectorFromString(methodName);
if ([parent respondsToSelector: selector])
    [parent performSelector: selector
                 withObject: value];

In this example, methodName just needs to be a string. You can also add an else clause, providing some kind of fallback in case the superclass doesn't implement this method. This is used, for example, to store all unrecognized XML elements in a dictionary so that other code can still access them.

The target-action pattern in AppKit has one extra feature that makes it a bit more useful. Every nib file contains a proxy object: the first responder. This object will deliver actions to the first object in the responder chain, if it responds to the relevant method, and if not then it will deliver them up the chain. If you connect an action to the -copy: method in the first responder, then every object in the responder chain will be given a chance to handle the action until one is found that implements a -copy: method. Again, you can implement similar functionality yourself, just testing every object in a group.

  • + Share This
  • 🔖 Save To Your Account