views:

1135

answers:

2

I have a simple protocol with a property:

@protocol StopsSource <NSObject>
@property (retain,readonly) NSArray * stops;
@end

I'm adding a key-value observer elsewhere to listen to changes to the "stops" property:

id<StopsSource> source = ...
[source addObserver:self
         forKeyPath:@"stops"
            options:NSKeyValueObservingOptionNew
            context:nil];

Code works as expected in that I get observeValueForKeyPath events when the "stops" property is changed. The real annoyance is a compiler warning on the addObserver call:

warning: '-addObserver:forKeyPath:options:context:' not found in protocol(s)

The 'addObserver' method is defined in a category to NSObject:

@interface NSObject(NSKeyValueObserverRegistration)

Is there any way to get XCode to drop this warning? It's my understanding that protocols can't adopt categories, so I'm not sure how to bring the NSKeyValueObserverRegistration methods into my protocol, short of copying the declarations into the protocol itself, which seems like a hack.

I know this is kind of a trivial problem, in that it's just a compiler warning, but I'm interested to know if there is a "right" way to address this.

A: 

I think you may be getting confused about what a protocol does; it is just defines a set of operations that can be implemented by another class.

The only thing in your protocol is a property.

Also, why are you declaring this to conform to the NSObject protocol? You don't need to do this because if you have a class that adopts your protocol, it will inherit from NSObject, and so will conform to . i.e

@interface YourClass : NSObject <StopSource> {
    // etc
@end
Abizern
Protocols can include properties in addition to methods. See the MyXMLSupport protocol example in:http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProtocols.html#//apple_ref/doc/uid/TP30001163-CH15-TPXREF148
Brian Ferris
Protocols often extend from NSObject so that they will respond to NSObject methods such as retain/release/respondsToSelector without raising a warning. For more info, see:http://stackoverflow.com/questions/679822/why-tack-a-protocol-of-nsobject-to-a-protocol-implementation
Brian Ferris
I see your points, but if all you are doing is mandating a single property accessor which you will have to create in the class which adopts the protocol it seems like overcomplication.
Abizern
And the point I was making about the adopting the NSObject protocol is that you don't need it if you define a class that inherits from NSObject to adopt the protocol. This should get rid of the warning as well.
Abizern
Plus, the NSObject protocol is not for protocols, it's so that you can create first-class objects (vis-a-vis Cocoa) that do not extend from the NSObject root.
Jason Coco
Points taken. I had always seen id<Protocol> and never ConcreteClass<Protocol>*. Thanks for the help!
Brian Ferris
id<Protocol> is just fine if you only want to use methods covered by the protocol :) In this case the person wanted to use a method covered by a totally separate protocol as well, so...
Jason Coco
+5  A: 

The real annoyance is a compiler warning on the addObserver call:

warning: '-addObserver:forKeyPath:options:context:' not found in protocol(s)

The 'addObserver' method is defined in a category to NSObject:

@interface NSObject(NSKeyValueObserverRegistration)

Is there any way to get XCode to drop this warning?

Xcode (lowercase c) is just showing you the warning; it's GCC, the compiler, that's giving you the warning in the first place.

You're confusing the class NSObject with the protocol NSObject. The NSObject class conforms to the NSObject protocol, among others, but protocols have no relation of their own to classes. Your StopsSource protocol, being a protocol, inherits from the NSObject protocol, not the NSObject class.

Your declaration only covers those two protocols, and not any specific class, so it doesn't include anything outside those protocols that the NSObject class may implement (such as KVO). That's why you get the warning.

As Jason Coco told you in his comment on your question, the solution is to change the declaration to use the NSObject class plus your protocol:

NSObject <StopsSource> *source = …;
Peter Hosey