特點
- 不同的類實現相似的功能
- 不同的類之間互相不干擾
聲明
可以聲明類方法、實例方法以及屬性。
例如:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
協議可以被任意對象實現,因此如果要聲明一個協議對象,類型應當設置為id
,
@interface XYZPieChartView : UIView
@property (weak) id <XYZPieChartViewDataSource> dataSource;
...
@end
Objective-C 使用尖括號表示某個類實現了某個協議;同時作為一個類的屬性時,協議對象應當被標記為 weak
,以防止循環引用導致的內存泄露。
默認情況下,在協議中聲明的方法是 必須實現
的,這意味著任何聲明了協議的對象都必須實現協議中聲明的方法或屬性。
通過 @ required
指令,在它之后聲明的方法或屬性為 必須實現
;
協議支持 可選
的方法或屬性
通過 @optional
指令,在它之后聲明的方法或屬性為 可選
;
如下表所示:
@protocol XYZPieChartViewDataSource
- (NSUInteger)numberOfSegments;
- (CGFloat)sizeOfSegmentAtIndex:(NSUInteger)segmentIndex;
@optional
- (NSString *)titleForSegmentAtIndex:(NSUInteger)segmentIndex;
- (BOOL)shouldExplodeSegmentAtIndex:(NSUInteger)segmentIndex;
@required
- (UIColor *)colorForSegmentAtIndex:(NSUInteger)segmentIndex;
@end
在代碼運行時需要判斷 可選
的方法或函數是否被實現
NSString *thisSegmentTitle;
if ([self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
繼承自其他協議的協議對象
- 協議可以繼承另外一個協議
- 當聲明一個協議時,它默認會繼承 NSObject 協議
- 實現某個協議的對象,需要同時實現這個協議和它的父協議
@protocol MyProtocol <NSObject>
...
@end
MyProtocol 協議繼承自 NSObject 協議
實現它的類不但需要實現 MyProtocol 協議,也要實現 NSObject 協議
遵照協議
一個類要遵照某個(某些)協議,寫法如下:
@interface MyClass : NSObject <MyProtocol, AnotherProtocol, YetAnotherProtocol>
...
@end
一般情況下,某個類需要實現的協議不會太多
如果一個類中實現了過多的協議,則需要考慮重構它,把這個類拆分為多個類,分別實現不同的協議
同時一個協議也不宜實現過多的功能,實際應用中,需要將一個大的協議盡量拆解成多個協議來實現多種功能
協議是匿名使用的
可以不需要知道某個實例是哪種類型,而調用協議方法
id <XYZFrameworkUtility> utility =
[frameworkObject anonymousUtility];
NSUInteger count = [utility numberOfSegments];
另一個 CoreData 的例子:
NSInteger sectionNumber = ...
id <NSFetchedResultsSectionInfo> sectionInfo =
[self.fetchedResultsController.sections objectAtIndex:sectionNumber];
NSInteger numberOfRowsInSection = [sectionInfo numberOfObjects];