Question

I was going through Programming with Objective-C document provided by Apple.

I'm trying to understand the following paragraph, but so far, unable to do so.

@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@required
- (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;
@end

@interface XYZPieCharView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
// some additional stuff
@end

If you attempt to call the respondsToSelector: method on an id conforming to the protocol as it’s defined above, you’ll get a compiler error that there’s no known instance method for it. Once you qualify an id with a protocol, all static type-checking comes back; you’ll get an error if you try to call any method that isn’t defined in the specified protocol. One way to avoid the compiler error is to set the custom protocol to adopt the NSObject protocol.

I'm getting confused at what is the difference between "Conforming to the protocol" and "Qualify some object with Protocol". And why should compiler generate an error if we send an id - that conforms to the protocol - the respondsToSelector message?

Was it helpful?

Solution

And why should compiler generate an error if we send an id - that conforms to the protocol - the respondsToSelector message

Yes, this is a very odd thing. Nowadays, under ARC, the compiler will throw an error if an object declared as id <XYZPieChartViewDataSource> is sent the respondsToSelector: method, the class method, or any other familiar basic NSObject instance method! Try it and see.

This seems strange, because id should permit any (known) message to be sent to it. However, id <XYZPieChartViewDataSource> is considered a completely specific type; the compiler will allow only messages that are part of the XYZPieChartViewDataSource protocol. One modern solution is this: don't use

id <XYZPieChartViewDataSource>

Instead, use

NSObject<XYZPieChartViewDataSource>*

This causes all the yummy goodness of NSObject to be included (as far as the compiler is concerned) in this object, including the ability to respond to respondsToSelector: and class and things like that.

Here's a paragraph I've inserted in my book, discussing this very issue:

Curiously, the compiler treats an object typed as id<SomeProtocol> very differently from how it treats an object typed as id, allowing only methods defined in SomeProtocol to be sent to that object. For example, suppose MyClass is defined with a delegate property typed as id<MyProtocol>. Then if obj is a MyClass instance, you can't speak of [obj.delegate class]; the compiler complains that class is not a known instance method! That's because obj.delegate is typed as id<MyProtocol>, and thus its only known instance method is doSomething:, the method defined by MyProtocol. We can work around this by casting obj.delegate to an id; a more elegant solution, when the definition of MyClass is up to us, is to declare the delegate property as NSObject<MyProtocol>* instead of id<MyProtocol>.

OTHER TIPS

Conforming to the protocol

This is when you @interface definition for your class specifies that the class implements (or conforms to) a protocol. This is information to the compiler to verify that the class does indeed implement the required methods.

@interface MyClass < MyProtocol >

Qualify some object with Protocol

This is adding extra information to a pointer type, usually an id, to tell the compiler that the object it references will implement the methods specified by the protocol (so they are valid to be called). The inverse of this is that any methods that aren't defined in the protocol are not valid to be called and you'll get a warning if you try.

id < MyProtocol > myObject = ...;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top