用OBJC编程 5 - Working with Protocols
协议定义了交互的消息@protocol XYZPieChartViewDataSource
- (NSUInteger) numberOfSegments;
- (CGFloat) sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
- (NSString *) titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
数据源作为View的一个属性,只要是符合协议的对象就可以,所以类型是id。@interface XYZPieChartView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
@end
委托和数据源属性通常声明为weak,以避免强引用循环。设置属性为一个不符合协议的对象,将会引起一个编译时警告。可选方法,使用@optional 和 @required@protocol XYZPieChartViewDataSource
- (NSUInteger) numberOfSegments;
- (CGFloat) sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *) titleForSegmentAtIndex:(NSUInteger)segmentIndex;
- (BOOL) shouldExplodeSegmentAtIndex:(NSUInteger)segementIndex;
@required
- (UIColor *) colorForSegmentAtIndex:(NSUInteger)segementIndex;
@end
运行时检查可选方法如果一个方法是可选的,那么在调用前应该检查它是否实现。NSString *thisSegmentTitle; // Local object variables are automatically initialized to nil
if([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]){
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
respondsToSelector: 方法用了一个selector,@selector。如上定义一个符合协议的id类型,调用respondsToSelector,会产生一个编译时错误,解决方案是声明对象符合NSObject协议从协议继承最佳实践是,你的协议依从NSObject协议。NSObject对象依从NSObject协议。一旦你的协议依从NSObject协议,那么依从你协议的任何对象都必须实现NSObject协议的方法,但因为它们应该是NSObject的子类,你就不必自己实现这些NSObject的方法。依从NSObject协议非常有用。@protocol MyProtocol <NSObject>
@end
comform 一个协议@interface MyClass : NSObject <MyProtocol, AnotherProtocol>
@end
如果一个类声明了大量的协议,意味着代码需要重构成多个小的类。一旦声明依从某个协议,就必须实现所有的required方法,和需要的optional方法,否则编译器会给出警告。方法的签名必须相同。Cocoa 和 Cocoa Touch 定义了大量的protocol- view的数据源协议
- view的委托协议delegate
- 一些类似的类,但是无继承关系,比如NSArray和NSDictionary依从NSCoding协议
- 一些OBJC语言级特性,也依赖协议,如一个容器需要依从NSFastEnumeration协议才能使用快速枚举fast enumeration;copy的属性依从NSCopying协议,否则会得到一个运行时异常。
为匿名使用协议
有时候,一个框架的开发者为了向使用者隐藏一个类,只把它的接口通过协议暴露
id <XYZFrameworkUtility> utility = [frameworkObject anonymousUtility];
例如NSFetcheResultsControllerNSInteger sectionNumber = //,,,
id <NSFetchedResultSectionInfo> sectionInfo =
[self.fetchedResultsController.sections objectAtIndex:sectionNumber];
NSInteger numberOfRowsInSection = [sectionInfo numberOfObjects];