Reputation: 17812
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?
Upvotes: 3
Views: 1196
Reputation: 535925
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 asid
, allowing only methods defined in SomeProtocol to be sent to that object. For example, suppose MyClass is defined with adelegate
property typed asid<MyProtocol>
. Then ifobj
is a MyClass instance, you can't speak of[obj.delegate class]
; the compiler complains thatclass
is not a known instance method! That's becauseobj.delegate
is typed asid<MyProtocol>
, and thus its only known instance method isdoSomething:
, the method defined by MyProtocol. We can work around this by castingobj.delegate
to anid
; a more elegant solution, when the definition of MyClass is up to us, is to declare thedelegate
property asNSObject<MyProtocol>*
instead ofid<MyProtocol>
.
Upvotes: 5
Reputation: 119031
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 = ...;
Upvotes: 4