- Introspection
- Protocols
- Extending Classes
- Informal Protocols
- Second-Chance Dispatch
- Summary
Informal Protocols
A fairly common pattern in Objective-C is the idea of an informal protocol, which is a collection of methods that a class may or may not implement. A common use is for delegate objects. In Java, it's very common for delegates to be expected to implement an interface. This approach often has a number of methods where several are implemented as methods with no body, which is needlessly verbose.
There are two ways of defining informal protocols in Objective-C. The first way is by defining a category on a base class (typically NSObject) that provides a null implementation of each method. This means that every class will respond to the messages in the interface, but only the ones that explicitly implement the method will do anything. You would put something like this in the source file that used the informal protocol:
@implementation NSObject (MyInformalProtocol) - (void) handleSomethingFrom:(id) sender {} @end
Then you simply send a handleSomethingFrom: message to the delegate object. Note that you don't need an @interface section to provide separation of interface and implementation for categories; the interface is private, and you don't want anything other than your class to be calling this method, so you don't publish an interface. While this technique is simple, it's not ideal in many respects, because it involves filling the root object's dispatch table with mostly-unused cruft (which can cause a slight performance degradation on the Apple runtime due to how it implements caching).
Another option is to perform runtime testing. If you send an object a respondsToSelector: message, you can find out whether it implements a named method. For delegates, you can then cache the IMP for the method and call this directly in the future. In your setDelegate: method, you would do something like this:
handleMethod = NULL; if([delegate respondsToSelector:@selector(handleSomethingFrom:)) { handleMethod = [delegate methodForSelector: @selector(handleSomethingFrom:)]; }
Then, where this is used, you would do the following:
// Equivalent to [delegate handleSomethingFrom:self]; if (NULL != handleMethod { handleMethod(delegate, @selector(handleSomethingFrom:), self); }
Objective-C 2.0 offers a third option, which is to use an @optional directive in a protocol declaration. This is largely a waste of space, since you still need to perform a runtime test to determine whether an object that conforms to a protocol actually does implement an optional method from that protocol.