views:

366

answers:

3

If a category I'm creating for a class adds methods that also fulfill the contract set out by a protocol, I'd like to flag that category class as implementing the protocol, and thereby indicate to the Obj-C pre-processor that the class effectively implements the protocol as well.

Example delegate (for clarity, thanks Ole!):

@protocol SomeDelegate <NSObject>
  - (void)someDelegateMessage;
@end

Example category:

@interface NSObject (SomeCategory) <SomeDelegate>
  - (void)someDelegateMessage;    
@end

And with an otherwise typical implementation

@implement NSObject (SomeCategory)
  - (void)someDelegateMessage {}
@end

When I actually try this, I get a warning for each NSObject method:

warning: incomplete implementation of category 'SomeCategory'

warning: method definition for '-description' not found

...

warning: method definition for '-isEqual:' not found

warning: category 'SomeCategory' does not fully implement the 'NSObject' protocol

Works fine if I remove <SomeDelegate> from the declaration, but of course NSObject isn't recognized as a SomeDelegate

+1  A: 

Any chance your protocol declaration includes the NSObject protocol? Like this:

@protocol SomeDelegate <NSObject>
...

That's where the warnings are coming from because now your category does not implement the full protocol. In the test code I just typed up, removing NSObject from the protocol removes the compiler warnings.

Ole Begemann
Yeah, that's how I've declared `SomeDelegate`. But removing `<NSObject>` from it--while removing the warnings on NSObject(SomeCategory)--would add new warnings every time the delegate (as an `id<SomeDelegate>`) is sent an NSObject message.I have to imagine there's something else I can do to have my cake and eat it too here.
Justin Searls
I cannot think of anything else, sorry.
Ole Begemann
No it won't cause new warnings. id's accept all messages without causing warnings, that is their function. See http://unixjunkie.blogspot.com/2008/03/id-vs-nsobject-vs-id.html for an explanation
Louis Gerbarg
Agree with Louis - get rid of the NSObject protocol definition, you don't need it. Any id variable can be sent any message, not just NSObject ones.
AlBlue
Yeah, plain `id` variables do not cause warnings, but if you declare `id<SomeDelegate> delegate` (what Justin would like to do), any NSObject message sent to `delegate` will cause a warning unless the protocol is declared `@protocol SomeDelegate <NSObject>`. Catch-22.
Ole Begemann
+1  A: 

If you want the compiler to shut up about sending <NSObject> messages (and its important that you remember that thats the protocol name, not the class name) then just use 'id' variables, not 'id' since thats you explicitly telling the compiler "This is an object which only implements the SomeDelegate protocol".

Alternately, use NSObject as your variable type instead.

Jeff Laing
A: 

A workaround is to declare the protocol on a category with no implementation, and implement the method in a different category, e.g.:

@interface NSObject (SomeCategory) <SomeDelegate>
  - (void)someDelegateMessage;    
@end
...
@implement NSObject (SomeCategory_Impl)
  - (void)someDelegateMessage {}
@end

If you do this, NSObject will be considered to conform to <SomeCategory> at compile time, and runtime checks for someDelegateMessage will succeed. However, conformsToProtocol: runtime checks will fail.

Of course, you should file a bug requesting that methods declared on the core class don’t generate warnings.

Ahruman
Accidentally naming the implementation of the category something else was how the codebase initially looked--correcting it was what caused my problem and precipitated this question. Changing it back has made my life easier; while I see the argument that this is a bug, I view it as an incidental workaround to a rather unsavory default behavior. (Luckily in my case it wouldn't make sense for any users of my library to need to call conformsToProtocol:)
Justin Searls