我正在浏览Apple提供的Programming with Objective-C文件。
我试图理解以下段落,但到目前为止,无法这样做。
@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
如果您尝试在id上调用respondsToSelector:方法 符合上面定义的协议,你会得到一个 编译器错误,没有已知的实例方法。一旦您 使用协议限定id,所有静态类型检查都会返回; 如果您尝试调用任何未定义的方法,您将收到错误 在指定的协议中。避免编译器错误的一种方法是 设置自定义协议以采用NSObject协议。
我对#34;符合协议&#34;之间的区别感到困惑。和#34;使用Protocol&#34;限定一些对象。如果我们发送一个符合协议的id - respondsToSelector
消息,编译器为什么会生成错误?
答案 0 :(得分:5)
如果我们发送一个符合协议的id,那么为什么编译器会生成错误 - respondsToSelector消息
是的,这是一件非常奇怪的事情。现在,在ARC下,如果声明为id <XYZPieChartViewDataSource>
的对象被发送respondsToSelector:
方法,class
方法或任何其他熟悉的基本NSObject实例方法,编译器将抛出错误!试试吧,看看。
这看起来很奇怪,因为id
应该允许将任何(已知的)消息发送给它。但是,id <XYZPieChartViewDataSource>
被认为是完全特定的类型;编译器将允许仅消息,这些消息是XYZPieChartViewDataSource协议的一部分。一个现代的解决方案是:不要使用
id <XYZPieChartViewDataSource>
相反,请使用
NSObject<XYZPieChartViewDataSource>*
这会导致在此对象中包含NSObject的所有美味(就编译器而言),包括响应respondsToSelector:
和class
以及类似的事情。< / p>
这是我在书中插入的一段,讨论了这个问题:
奇怪的是,编译器将类型为
id<SomeProtocol>
的对象与处理类型为id
的对象的处理方式大不相同,只允许将SomeProtocol中定义的方法发送到该对象。例如,假设MyClass定义为delegate
属性,类型为id<MyProtocol>
。如果obj
是MyClass实例,则不能说[obj.delegate class]
;编译器抱怨class
不是已知的实例方法!这是因为obj.delegate
的类型为id<MyProtocol>
,因此其仅已知实例方法为doSomething:
,即MyProtocol定义的方法。我们可以通过将obj.delegate
投射到id
来解决此问题。一个更优雅的解决方案,当MyClass的定义取决于我们时,是将delegate
属性声明为NSObject<MyProtocol>*
而不是id<MyProtocol>
。
答案 1 :(得分:4)
符合协议
这是当您的类的@interface
定义指定该类实现(或符合)协议时。这是编译器验证类确实实现了所需方法的信息。
@interface MyClass < MyProtocol >
使用Protocol
限定某些对象
这是向指针类型添加额外信息,通常是id
,告诉编译器它引用的对象将实现协议指定的方法(因此它们可以被调用)。与此相反的是,协议中未定义的任何方法都无法调用,如果您尝试,则会收到警告。
id < MyProtocol > myObject = ...;