OC中協(xié)議是聲明方法的集合體,由類實(shí)現(xiàn)協(xié)議聲明的所有方法,稱之為類遵循(conform)方法。
協(xié)議的使用
協(xié)議的聲明
@protocol 協(xié)議名
聲明方法;
...
@end
協(xié)議的采用(adopt)
@interface 類名 : 超類名 <協(xié)議名>
{
聲明實(shí)例變量;
...
}
聲明方法;
...
@end
- 類采用協(xié)議后,需要在實(shí)現(xiàn)文件中實(shí)現(xiàn)協(xié)議中聲明的方法。
- 類可以采用多個(gè)協(xié)議,在尖括號(hào)中用逗號(hào)分隔。
- 一個(gè)協(xié)議中不能聲明兩個(gè)選擇器相同而簽名不同的方法。
協(xié)議可以繼承協(xié)議
@protocol 協(xié)議名1 <協(xié)議名2>
聲明方法;
...
@end
指定協(xié)議的類型聲明
聲明某個(gè)對(duì)象適用于某個(gè)協(xié)議
id <協(xié)議名> obj;
可以將這個(gè)對(duì)象作為方法參數(shù),表明只要遵循了該協(xié)議的對(duì)象可以傳入。
協(xié)議的前置聲明
@protocol 協(xié)議名
協(xié)議適用性檢查
在運(yùn)行時(shí)可以動(dòng)態(tài)的檢查對(duì)象是否適用于某個(gè)協(xié)議。
//aProtocol參數(shù)指定的協(xié)議和類適用是,返回YES
+ (BOOL) conformsToProtocol: (Protocol *) aProtocol
//接收器類和參數(shù)aProtocol指定的協(xié)議適用時(shí),返回YES
- (BOOL) conformsToProtocol: (Protocol *) aProtocol
必選和可選
在Objective-C 2.0中規(guī)定了一項(xiàng)新規(guī)定,使用@optional和@required來標(biāo)注協(xié)議方法為可選的和必須實(shí)現(xiàn)的,默認(rèn)為@required,編譯器會(huì)警告沒有實(shí)現(xiàn)的@required方法,而不會(huì)警告@optional修飾的方法。
在采用協(xié)議的時(shí)候,需要?jiǎng)討B(tài)的檢查方法是否可用。使用responsToSelector:方法來檢查是否實(shí)現(xiàn)了某個(gè)方法
委托(Delegate)
委托模式是一種設(shè)計(jì)模式,在OC中,委托通過協(xié)議的方式實(shí)現(xiàn)。
委托可以用來監(jiān)聽、通知或者代理其他對(duì)象做一些事。這里通過租客通過中介租房的例子來介紹委托的使用方式。
租客想要租房子,但自己沒有時(shí)間,于是找了中介幫忙租,租客向中介提供了一個(gè)租房的協(xié)議,協(xié)議的目的是讓中介幫忙找房子,但租客不關(guān)心找房子具體的過程。
首先看類圖

定義一個(gè)協(xié)議RentProtocol,聲明一個(gè)尋找房子的方法findingHouse
定義一個(gè)中介類Agent,實(shí)現(xiàn)RentProtocol協(xié)議
定義一個(gè)租客類Renter,聲明一個(gè)代理rentDelegate,這個(gè)代理必須遵守RentProtocol協(xié)議
協(xié)議部分代碼
@class Renter;
@protocol RentProtocol <NSObject>
- (BOOL)findingHouse:(Renter *)renter;//找房子的方法
@end
中介部分代碼
@interface Agent : NSObject <RentProtocol>
@property (strong, nonatomic) NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
@implementation Agent
- (instancetype)initWithName:(NSString *)name{
_name = name;
return self;
}
- (BOOL)findingHouse:(Renter *)renter{
NSLog(@"%@的正在幫%@找房子", self.name, renter.name);
return YES;
}
@end
租客部分代碼
@interface Renter : NSObject
@property (strong, nonatomic) NSString *name;//租客的名字
@property (strong, nonatomic) id <RentProtocol> rentDelegate;
- (instancetype)initWithName:(NSString *)name;
- (void)findHouseFromRenter;
@implementation Renter
- (instancetype)initWithName:(NSString *)name{
_name = name;
return self;
}
- (void)findHouseFromRenter{
NSLog(@"%@準(zhǔn)備找中介租房子", self.name);
BOOL checkProtocol = [self.rentDelegate conformsToProtocol:@protocol(RentProtocol)];//
// BOOL checkProtocol = [self.rentDelegate respondsToSelector:@selector(findingHouse:)];
if(!checkProtocol){
NSLog(@"沒有找到代理,打包回家");
} else{
if([self.rentDelegate findingHouse:self]){
NSLog(@"找到房子了!");
}
}
}
@end
上面的代碼使用了兩種方法判斷rentDelegate是否遵守了協(xié)議,conformsToProtocol判斷是否遵守該協(xié)議,而respondsToSelector判斷協(xié)議是否實(shí)現(xiàn)了findingHouse方法,通常使用后者,比如某些類遵守了協(xié)議但并沒有實(shí)現(xiàn)需要用到的方法。
main函數(shù)和打印結(jié)果
int main(int argc, const char * argv[]) {
@autoreleasepool {
Renter *renter = [[Renter alloc] initWithName:@"wilson"];
Agent *agent = [[Agent alloc] initWithName:@"黑心中介"];
renter.rentDelegate = agent;
[renter findHouseFromRenter];
}
return 0;
}
2018-06-06 11:50:25.342768+0800 DelegateStudy[78708:10208881] wilson準(zhǔn)備找中介租房子
2018-06-06 11:50:25.343010+0800 DelegateStudy[78708:10208881] 黑心中介正在幫wilson找房子
2018-06-06 11:50:25.343027+0800 DelegateStudy[78708:10208881] 找到房子了!
在這個(gè)例子中,我們只定義了一個(gè)黑心中介的類來幫租客找房子,實(shí)際上只要遵守了這個(gè)協(xié)議的任何一個(gè)類,都可以作為租客的找房子代理者,例如租客的一個(gè)朋友也遵守了協(xié)議,實(shí)現(xiàn)了協(xié)議中的方法,同樣可以將該朋友的對(duì)象傳遞給租客的rentDelegate屬性。
協(xié)議使得開發(fā)更加靈活,面向協(xié)議(接口)編程也是一種提高架構(gòu)靈活性,降低耦合性的一種非常好的方式。