來源于 Ry’s Objective-C Tutorial - RyPress
一個(gè)學(xué)習(xí)Objective-C基礎(chǔ)知識的網(wǎng)站.
個(gè)人覺得很棒,所以決定抽時(shí)間把章節(jié)翻譯一下.
本人的英語水平有限,有讓大家誤解或者迷惑的地方還請指正.
原文地址:http://rypress.com/tutorials/objective-c/protocols.html
僅供學(xué)習(xí),如有轉(zhuǎn)摘,請注明出處.
協(xié)議是一組可以讓任何類實(shí)現(xiàn)的相關(guān)屬性和方法.它們比一個(gè)普通的類接口更靈活,因?yàn)樗鼈兛梢宰屇阍诓幌嚓P(guān)的類之間重用一個(gè)API.這就讓表示現(xiàn)有類之間的橫向關(guān)系成為可能.

這只是涵蓋協(xié)議基礎(chǔ)知識中的一部分(內(nèi)容).我們將會(huì)學(xué)習(xí)協(xié)議是如何與OC的動(dòng)態(tài)機(jī)制相匹配的.
創(chuàng)建協(xié)議
步驟略.
創(chuàng)建名為StreetLegal的協(xié)議.
該協(xié)議約束了合法交通工具的必須行為.在協(xié)議中定義這些特性(屬性或者方法)讓你可以將它們應(yīng)用到任意類,而不是必須從同樣地抽象父類繼承(才能實(shí)現(xiàn)這個(gè)目標(biāo)).
StreetLegal協(xié)議的一個(gè)簡單版本內(nèi)容像下面這樣:
// StreetLegal.h
#import <Foundation/Foundation.h>
@protocol StreetLegal <NSObject>
- (void)signalStop;
- (void)signalLeftTurn;
- (void)signalRightTurn;
@end
任何遵守該協(xié)議的類都必須得保證實(shí)現(xiàn)它的所有方法.在協(xié)議名之后的<NSObject>是表明StreetLegal Protocol包含NSObject 協(xié)議(不要與Object類混淆了).實(shí)際上,任何一個(gè)遵守StreetLegal協(xié)議的類都被要求遵守NSObject協(xié)議.
遵守協(xié)議
一個(gè)類可以通過在其類名/超類名之后添加尖括號(在尖括號內(nèi)寫上協(xié)議名)來遵守上述(協(xié)議中)的API.創(chuàng)建一個(gè)Bicycle類,并修改如下.請注意,在你使用協(xié)議之前也需要先將其導(dǎo)入.
// Bicycle.h
#import <Foundation/Foundation.h>
#import "StreetLegal.h"
@interface Bicycle : NSObject <StreetLegal>
- (void)startPedaling;
- (void)removeFrontWheel;
- (void)lockToStructure:(id)theStructure;
@end
遵守協(xié)議就像是把StreetLegal.h中的所有方法加到Bicycle.h中.這與Bicycle繼承自一個(gè)超類的效果完全一樣.可以通過用逗號分隔來遵守多個(gè)協(xié)議(比如,<StreetLegal, SomeOtherProtocol>).
Bicycle的實(shí)現(xiàn)沒什么特別-僅需保證Bicycle.h與StreetLegal.h中的方法全部被實(shí)現(xiàn)了就行.
// Bicycle.m
#import "Bicycle.h"
@implementation Bicycle
- (void)signalStop {
NSLog(@"Bending left arm downwards");
}
- (void)signalLeftTurn {
NSLog(@"Extending left arm outwards");
}
- (void)signalRightTurn {
NSLog(@"Bending left arm upwards");
}
- (void)startPedaling {
NSLog(@"Here we go!");
}
- (void)removeFrontWheel {
NSLog(@"Front wheel is off."
"Should probably replace that before pedaling...");
}
- (void)lockToStructure:(id)theStructure {
NSLog(@"Locked to structure. Don't forget the combination!");
}
@end
現(xiàn)在,當(dāng)你使用Bicycle類時(shí),你就能假定它會(huì)對協(xié)議中定義的API做出響應(yīng)了.感覺就像signalStop,signalLeftTurn, and signalRightTurn (這些方法)都是在Bicycle.h中聲明地.
// main.m
#import <Foundation/Foundation.h>
#import "Bicycle.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Bicycle *bike = [[Bicycle alloc] init];
[bike startPedaling];
[bike signalLeftTurn];
[bike signalStop];
[bike lockToStructure:nil];
}
return 0;
}
使用協(xié)議進(jìn)行類型檢查
跟類一樣,協(xié)議也能用于變量類型檢查.為了保證一個(gè)對象遵守某個(gè)協(xié)議,可以在變量聲明時(shí)將協(xié)議名寫在數(shù)據(jù)類型后面,如下所示.下面的代碼段假設(shè)你已經(jīng)創(chuàng)建好了一個(gè)遵守StreetLegal協(xié)議的Car類:
// main.m
#import <Foundation/Foundation.h>
#import "Bicycle.h"
#import "Car.h"
#import "StreetLegal.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
id <StreetLegal> mysteryVehicle = [[Car alloc] init];
[mysteryVehicle signalLeftTurn];
mysteryVehicle = [[Bicycle alloc] init];
[mysteryVehicle signalLeftTurn];
}
return 0;
}
即使Car與Bicycle都集成自相同的超類也沒關(guān)系-實(shí)際上,它們都遵守StreetLegal協(xié)議.所以我們可以通過聲明id<StreetLegal>變量來存儲(chǔ)它們.這是一個(gè)展示無關(guān)類之間如何使用公有功能的例子.
也可以使用NSObject協(xié)議中定義的conformToProtocol:方法來檢查對象是否遵守某個(gè)協(xié)議.它將一個(gè)協(xié)議對象當(dāng)做一個(gè)參數(shù),該參數(shù)可以通過@protocol()指令獲得.這與@selector()指令很類似,但是你需要傳遞的是協(xié)議名而不是方法名,如下所示:
if ([mysteryVehicle conformsToProtocol:@protocol(StreetLegal)]) {
[mysteryVehicle signalStop];
[mysteryVehicle signalLeftTurn];
[mysteryVehicle signalRightTurn];
}
這種使用協(xié)議的方式就像是在說,"保證這個(gè)對象有這組特殊的功能."對動(dòng)態(tài)類型(機(jī)制)來說,這是一個(gè)強(qiáng)大的工具,因?yàn)樗茏屇阍诓挥貌傩母裁搭愋偷膶ο蟠蚪坏赖那闆r下,使用一個(gè)定義良好的API.
現(xiàn)實(shí)世界(OC)中的協(xié)議
在你日常的iOS與OS X開發(fā)中,你會(huì)遇到更實(shí)際使用(協(xié)議)的情況.任何一個(gè)app的入口都是"application delegate(應(yīng)用程序代理)",一個(gè)能處理程序生命周期中重要事件的對象.UIKit Framework僅僅讓你遵守一個(gè)協(xié)議,而不是強(qiáng)迫(要求)這個(gè)delegate繼承某個(gè)特殊的超類.
@interface YourAppDelegate : UIResponder <UIApplicationDelegate>
任何一個(gè)能響應(yīng)UIApplicationDelegate中定義的方法的對象都能作為應(yīng)用程序代理.當(dāng)重新組織應(yīng)用程序(代碼)時(shí),通過協(xié)議替代子類(繼承)來實(shí)現(xiàn)代理設(shè)計(jì)模式給了開發(fā)人員更多回旋余地(更容易解耦).
你可以在Ry's Cocoa Tutorial的Interface Builder章節(jié)查看具體的例子.它使用項(xiàng)目中默認(rèn)的app代理去響應(yīng)用戶輸入.
總結(jié)
這個(gè)模塊中,我們(在我們已收集的東西)添加了另一個(gè)組織(代碼)工具.協(xié)議是一個(gè)讓專有文件能抽象共享屬性和方法的途徑.這有助于減少冗余代碼,并允許你動(dòng)態(tài)地檢查一個(gè)對象是否支持任意一組功能.
在Cocoa 框架中你會(huì)發(fā)現(xiàn)很多協(xié)議.一個(gè)常用的情況是,讓你不用子類化某些類(的情況下)就可修改它們的行為.比如,[Table View],[Outline View]以及[Collection View]這些UI組件都使用數(shù)據(jù)源(data source)以及代理對象去設(shè)定它們內(nèi)部的行為.數(shù)據(jù)源和代理都被定義成協(xié)議,因此,可以在任何對象中實(shí)現(xiàn)必要的方法.
下個(gè)模塊將會(huì)介紹分類.
(which are a flexible option for modularizing classes and providing opt-in support for an API.)大致意思:是實(shí)現(xiàn)類模塊化以及給API提供可選支持的彈性(靈活)選擇
寫于15年09月08號