不少第三方框架中,有這樣的一種用法:有一個.h的頭文件,它裏面只有協議的聲明,並且沒有對應的.m實現文件。一般這種文件就用來專職聲明協議的做用了。git
這裏舉一個你們都能看到和下載的例子,優秀的第三方圖文混排框架:TYAttributedLabel。github
這個框架裏面有這樣一段代碼:bash
// 添加響應點擊rect
- (void)addRunRectDictionary:(NSDictionary *)runRectDictionary
{
if (runRectDictionary.count < _runRectDictionary.count) {
NSMutableArray *drawStorageArray = [[_runRectDictionary allValues]mutableCopy];
// 剔除已經畫出來的
[drawStorageArray removeObjectsInArray:[runRectDictionary allValues]];
// 遍歷不會畫出來的
for (id<TYTextStorageProtocol>drawStorage in drawStorageArray) {
if ([drawStorage conformsToProtocol:@protocol(TYViewStorageProtocol)]) {
[(id<TYViewStorageProtocol>)drawStorage didNotDrawRun];
}
}
}
_runRectDictionary = runRectDictionary;
}
複製代碼
能夠先關注這個:框架
if ([drawStorage conformsToProtocol:@protocol(TYViewStorageProtocol)])
複製代碼
這行代碼主要作一個是否服從協議的判斷。這個協議是聲明在TYTextStorageProtocol.h文件裏面的。你們查看這個文件可知,它裏面主要聲明瞭幾個協議,並且沒有對應的.m文件。ui
打開TYTextStorageProtocol.h查看協議的代碼:atom
@protocol TYViewStorageProtocol <NSObject>
/**
* 設置所屬的view
*/
- (void)setOwnerView:(UIView *)ownerView;
/**
* 不會把你繪畫出來
*/
- (void)didNotDrawRun;
@end
複製代碼
[(id<TYViewStorageProtocol>)drawStorage didNotDrawRun];
複製代碼
這句話裏面的didNotDrawRun
方法是前面那個協議聲明的方法,因此,只有當前面作了判斷是否服從該協議以後,纔可將暫時仍是個id類型的drawStorage對象進行轉換,轉成一個服從該協議的對象,進而執行協議方法。spa
對象的轉換:.net
(id<TYViewStorageProtocol>)drawStorage
複製代碼
至於一個對象是否「服從」的標準:就是該對象的類或其父類的@interface後面跟上一個協議,並實現協議的方法。code
接下來再這裏的drawStorage對象,是怎樣選擇「服從」 協議TYViewStorageProtocol
的:orm
#import "TYDrawStorage.h"
@interface TYViewStorage : TYDrawStorage<TYViewStorageProtocol>
@property (nonatomic, strong) UIView *view; // 添加view
@end
複製代碼
//TYViewStorageProtocol
- (void)didNotDrawRun
{
[_view removeFromSuperview];
}
複製代碼
上面的協議聲明有這樣一行:
@protocol TYViewStorageProtocol <NSObject>
複製代碼
這是協議的繼承用法,該自定義協議繼承自 根協議 ,協議的繼承具備多繼承的特色。
要注意的是,這裏的 根協議 與常見的 基類 NSObject是兩種概念:一個是類,一個是協議。NSObject類服從NSObject協議。具體的關係可參考筆者的另外一篇 iOS·NSObject的兩種含義:類與協議