符合协议的id与使用协议限定id

时间:2014-04-01 19:01:44

标签: ios objective-c cocoa methods protocols

我正在浏览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消息,编译器为什么会生成错误?

2 个答案:

答案 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 = ...;