Ios 符合协议的id vs使用协议限定id
我正在浏览苹果公司提供的文件 我试图理解下面的一段,但到目前为止,我还不能理解Ios 符合协议的id vs使用协议限定id,ios,objective-c,cocoa,methods,protocols,Ios,Objective C,Cocoa,Methods,Protocols,我正在浏览苹果公司提供的文件 我试图理解下面的一段,但到目前为止,我还不能理解 @protocol XYZPieChartViewDataSource - (NSUInteger)numberOfSegments; - (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex; @optional - (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex; @required -
@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
@协议XYZPieChartViewDataSource
-(整数)段数;
-(CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@可选的
-(NSString*)标题为分段索引:(NSInteger)分段索引;
@必需的
-(UIColor*)colorForSegmentAtIndex:(NSUPINTEGER)段索引;
@结束
@接口XYZPieCharView:UIView
@属性(弱)id数据源;
//一些额外的东西
@结束
如果尝试调用id上的respondsToSelector:方法
按照上面定义的协议,您将得到
编译器错误,没有已知的实例方法。一旦你
使用协议限定id,所有静态类型检查返回;
如果您试图调用任何未定义的方法,将出现错误
在指定的协议中。避免编译器错误的一种方法是
设置自定义协议以采用NSObject协议
我对“遵守协议”和“用协议限定某个对象”之间的区别感到困惑。如果我们发送一个符合协议的id,respondsToSelector
消息,为什么编译器会产生错误
符合议定书
这是当类的定义指定类实现(或符合)协议时。这是编译器用来验证类是否确实实现了所需方法的信息
@interface MyClass < MyProtocol >
如果我们发送一个符合协议的id——respondsToSelector消息,为什么编译器会产生错误呢
是的,这是一件很奇怪的事情。现在,在ARC下,如果声明为id
的对象被发送到响应选择器:
方法、类
方法或任何其他熟悉的基本NSObject实例方法,编译器将抛出错误!试试看
这似乎很奇怪,因为id
应该允许向其发送任何(已知)消息。然而,id
被认为是一种完全特定的类型;编译器将只允许属于XYZPieChartViewDataSource协议一部分的消息。一个现代的解决方案是:不要使用
id <XYZPieChartViewDataSource>
id
相反,使用
NSObject<XYZPieChartViewDataSource>*
NSObject*
这将使NSObject的所有优点(就编译器而言)都包含在这个对象中,包括响应respondsToSelector:
和class
之类的功能
这是我在书中插入的一段,讨论了这个问题:
奇怪的是,编译器对待类型化为id
的对象与对待类型化为id
的对象非常不同,只允许将SomeProtocol中定义的方法发送到该对象。例如,假设MyClass是用类型为id
的delegate
属性定义的。如果obj
是一个MyClass实例,那么就不能说[obj.delegate class]
;编译器抱怨class
不是已知的实例方法!这是因为obj.delegate
被键入为id
,因此它唯一已知的实例方法是doSomething:
,这是MyProtocol定义的方法。我们可以通过将obj.delegate
转换为id
来解决这个问题;当MyClass的定义由我们决定时,一个更优雅的解决方案是将delegate
属性声明为NSObject*
,而不是id
由于到目前为止我已经实现了许多协议数据源,我无法确切地说出这句话想要解释什么。然而,我使用的协议没有问题。以我个人的拙见,我认为在实际情况下实现它,看看它在需要协议时是如何工作和感觉的是最快的学习方法。让协议扩展
意味着在运行时得到的对象可能是NSProxy
,指定协议比指定类类型(通常被认为是良好实践)更具限制性。那么,使用协议将类指定为NSObject
有什么好处呢?个人偏好或我遗漏了什么?@Wain让协议指定它符合
协议也可以。我从未使用过Nproxy,因此在实践中,我从未出现过这种区别。另外,我直接从苹果公司的格雷格·帕克那里得到了NSObject*
的想法,我倾向于按照他说的去做:)我对我的答案做了一些修改。当然这一点也不“奇怪”,尽管乍一看语法可能有些混乱。将变量声明为类类型就是断言引用对象提供了类的方法等,而不断言其他任何内容。将变量声明为协议类型应该是与此直接并行的(Java中也是如此)。这里没什么奇怪的。唯一的问题是语法。由于协议出现在语法中一个类后的括号中,因此使用什么来表示“仅协议”id
是有意义的,因为“任何内容和协议”是一个冗余规范。@CRD嗯,不同的人对不同的事情感到惊讶。我所能告诉你的是,当我第一次对键入为id
的引用说respondsToSelector:
时,编译器向我吐了一口唾沫,我非常惊讶@matt-我们确实是:-)但是我建议您面临的问题更多地与默认情况下不包括NSObject协议的协议有关,而不是与“协议类型变量”的语法有关。很少有Obj-C程序员会错过一个接口上的NSObject基础(并且当他们这样做时会对错误感到惊讶),但是有多少人会错过一个协议上的NSObject基础呢?Java没有相同的问题,因为只有一个根对象,所以无论什么都必须实现它的方法。O
NSObject<XYZPieChartViewDataSource>*