Defining categories for protocols in Objective-C?

Jochen picture Jochen · Oct 5, 2009 · Viewed 22.8k times · Source

In Objective-C, I can add methods to existing classes with a category, e.g.

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

Is it also possible to do this with protocols, i.e. if there was a NSString protocol, something like:

@interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

I want to do this since I have several extensions to NSObject (the class), using only public NSObject methods, and I want those extensions also to work with objects implementing the protocol .

To give a further example, what if I want to write a method logDescription that prints an object's description to the log:

- (void) logDescription {
    NSLog(@"%@", [self description]);
}

I can of course add this method to NSObject, but there are other classes that do not inherit from NSObject, where I'd also like to have this method, e.g. NSProxy. Since the method only uses public members of protocol , it would be best to add it to the protocol.

Edit: Java 8 now has this with "virtual extension methods" in interfaces: http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf. This is exactly what I would like to do in Objective-C. I did not see this question earning this much attention...

Regards, Jochen

Answer

Dave DeLong picture Dave DeLong · Oct 5, 2009

Short answer: No.

Long answer: how would this work? Imagine you could add methods to existing protocols? How would this work? Imagine we wanted to add another method to NSCoding, say -(NSArray *) codingKeys; This method is a required method that returns an array of the keys used to encoding the object.

The problem is that there are existing classes (like, say NSString) that already implement NSCoding, but don't implement our codingKeys method. What should happen? How would the pre-compiled framework know what to do when this required message gets sent to a class that does not implement it?

You could say "we can add the definition of this method via a category" or "we could say that any methods added via these protocol categories are explicitly optional". Yes, you could do this and theoretically get around the problem I've described above. But if you're going to do that, you might as well just make it a category in the first place, and then check to make sure the class respondsToSelector: before invoking the method.