需要了解ios協(xié)議, 首先看一個(gè)代碼示例:
- 流氓協(xié)議(YHBadManDelegate.h)
#import <Foundation/Foundation.h>
/**流氓協(xié)議*/
@protocol BadManDelegate <NSObject>
@required // 必須實(shí)現(xiàn)的方法
/**吃*/
- (void) eat;
/**騙*/
- (void) lie;
@optional // 可選實(shí)現(xiàn)的方法
- (void) drink;
@end
- 君子協(xié)議(GentlemanDelegate.h)
/**君子協(xié)議*/
@protocol GentlemanDelegate <NSObject>
// 協(xié)議內(nèi)容只能有方法不能有屬性
// 協(xié)議方法
/**動(dòng)口不動(dòng)手*/
- (void) fight;
/**愛錢取之有道*/
- (void) loveMoney;
@end
- 初始化遵守協(xié)議的對(duì)象
#import <Foundation/Foundation.h>
#import "BadManDelegate.h"
#import "GentlemanDelegate.h"
// 遵守協(xié)議的類就是代理類; 如果一個(gè)類遵守了協(xié)議, 就要去實(shí)現(xiàn)協(xié)議方法;
/**遵守流氓協(xié)議的代理*/
// 一個(gè)類可以同時(shí)遵守多個(gè)協(xié)議, 在一個(gè)<>中多個(gè)協(xié)議名用逗號(hào)隔開
@interface YHPerson : NSObject <BadManDelegate, GentlemanDelegate>
@end
@interface YHStudent : NSObject <BadManDelegate>
- (void) study;
@end
- 實(shí)現(xiàn)協(xié)議
#import "YHPerson.h"
@implementation YHPerson
- (void) eat {
NSLog(@"正在吃霸王餐!!");
}
- (void) lie {
NSLog(@"在撒謊!!");
}
- (void) fight {
NSLog(@"動(dòng)口不動(dòng)手!!");
}
- (void) loveMoney {
NSLog(@"愛錢取之有道!!");
}
@end
@implementation YHStudent
// 實(shí)現(xiàn)學(xué)生相關(guān)的方法
- (void) study {
NSLog(@"Good Good Study, Day Day Up.");
}
// 實(shí)現(xiàn)流氓協(xié)議的方法
- (void) eat {
NSLog(@"吃完帶搶");
}
- (void) lie {
NSLog(@"處處留情!!");
}
@end
這里說明幾點(diǎn):
- 一個(gè)協(xié)議可以擴(kuò)展自另一個(gè)協(xié)議,例如上面BadManDelegate就擴(kuò)展自NSObject,如果需要擴(kuò)展多個(gè)協(xié)議中間使用逗號(hào)分隔;
- 和其他高級(jí)語言中接口不同的是協(xié)議中定義的方法不一定是必須實(shí)現(xiàn)的,我們可以通過關(guān)鍵字進(jìn)行@required和@optional進(jìn)行設(shè)置,如果不設(shè)置則默認(rèn)是@required(注意ObjC是弱語法,即使不實(shí)現(xiàn)必選方法編譯運(yùn)行也不會(huì)報(bào)錯(cuò));
- 協(xié)議通過<>進(jìn)行實(shí)現(xiàn),一個(gè)類可以同時(shí)實(shí)現(xiàn)多個(gè)協(xié)議,中間通過逗號(hào)分隔;
- 協(xié)議的實(shí)現(xiàn)只能在類的聲明上,不能放到類的實(shí)現(xiàn)上(也就是說必須寫成@interface YHPerson:NSObject <AnimalDelegate>而不能寫成@implementation YHPerson<AnimalDelegate>);
- 協(xié)議中不能定義屬性、成員變量等,只能定義方法;
由上例可以看出,iOS中的協(xié)議其實(shí)和生活中的協(xié)議基本上是一樣的,比如生活中簽訂的就業(yè)協(xié)議、保密協(xié)議以及一些合同等等。而協(xié)議本身就是一系列的條款及規(guī)定(在OC中的協(xié)議主要看的是甲方對(duì)乙方指定的規(guī)定)。
-
協(xié)議的基本概念
- 委托: 即簽訂協(xié)議時(shí)的甲方(指定協(xié)議)
- 代理: 即簽訂協(xié)議時(shí)的乙方(遵守協(xié)議)
- 協(xié)議: 甲方對(duì)乙方的規(guī)定、要求(OC中的實(shí)質(zhì)就是一系列的方法)
-
協(xié)議的特點(diǎn)
- 一個(gè)類可以同時(shí)遵守多個(gè)協(xié)議(遵守協(xié)議后必須實(shí)現(xiàn)協(xié)議方法)
- 同一個(gè)協(xié)議可以被多個(gè)類遵守, 不同的類中協(xié)議方法可以有不同的實(shí)現(xiàn)
-
協(xié)議的主要要求
遵守協(xié)議就是要做到協(xié)議上規(guī)定的內(nèi)容, 遵守什么樣的協(xié)議就需要做什么樣的對(duì)象例如:
1、君子協(xié)議
協(xié)議內(nèi)容: 君子動(dòng)口不動(dòng)手、君子愛財(cái)取之有道、君子愛美取只有禮等
君子: 遵守君子協(xié)議的人
2、流氓協(xié)議
協(xié)議內(nèi)容: 吃喝嫖賭、坑蒙拐騙偷等
流氓: 遵守流氓協(xié)議的人
- 使用協(xié)議代理解決問題需要找到三要素(協(xié)議、代理、委托)
- 委托: 老板 (想要做某件事情, 但是自己沒有能力去做, 需要?jiǎng)e人來幫他完成)
- 協(xié)議: 會(huì)iOS開發(fā) (委托對(duì)代理的要求, 委托想要代理幫他做的事情)
- 代理: 遵守協(xié)議的對(duì)象 (實(shí)際做事情的對(duì)象)
使用協(xié)議代理解決問題: (如果一個(gè)對(duì)象想要做一件事情(完成一個(gè)功能), 但是自己做不到, 需要一個(gè)可以做到的對(duì)象來幫他完成, 考慮使用協(xié)議代理)
??場(chǎng)景: 老板想要做一個(gè)iOS項(xiàng)目
??分析: 老板想做iOS項(xiàng)目, 但是自己不會(huì)做, 找一個(gè)會(huì)iOS開發(fā)的人來幫他做
- YHBoss.h
#import <Foundation/Foundation.h>
//2.協(xié)議
/**聲明協(xié)議*/
@protocol StaffDelegate <NSObject>
/**會(huì)IOS開發(fā)(做開發(fā))*/
- (void) codeIOS;
@end
// 1. 委托
// 委托需要一個(gè)遵守協(xié)議的對(duì)象來幫他做事情 (委托需要一個(gè)代理)
/**委托類(制定協(xié)議)*/
@interface YHBoss : NSObject
// 任何遵守協(xié)議的類創(chuàng)建的對(duì)象都可以作為老板的代理
// 注意: delegate要用weak修飾(防止循環(huán)引用造成對(duì)象不能銷毀)
/**代理*/
@property (nonatomic, weak) id <StaffDelegate> delegate;
// 告訴代理何時(shí)去做事情
/**告訴代理*/
- (void) askStaffWorking;
@end
- YHBoss.m
#import "YHBoss.h"
@implementation YHBoss
//委托告訴代理做事
- (void) askStaffWorking {
NSLog(@"老板告訴員工開工");
// 代理開始做事情
[self.delegate codeIOS];
}
@end
- YHPerson.h
#import <Foundation/Foundation.h>
#import "YHBoss.h"
// 3.代理(遵守協(xié)議, 實(shí)現(xiàn)協(xié)議方法)
/**代理*/
@interface YHPerson : NSObject <StaffDelegate>
@end
- YHPerson.m
#import "YHPerson.h"
#import "YHBoss.h"
@implementation YHPerson
// 判斷一個(gè)對(duì)象是否實(shí)現(xiàn)了某個(gè)方法
// (這里判斷self.delegate是否實(shí)現(xiàn)了buyPhone方法)
if ([self.delegate respondsToSelector:@selector(codeIOS)]) {
// 代理開始做事情
[self.delegate codeIOS];
}
@end
- main.h
#import <Foundation/Foundation.h>
#import "YHPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 1.首先需要一個(gè)boss
YHBoss *boss = [[YHBoss alloc] init];
// 2.需要一個(gè)員工
YHPerson *person = [[YHPerson alloc] init];
// 3.讓員工成為老板的代理
boss.delegate = person;
// 4.老板喊開工
[boss askStaffWorking];
}
return 0;
}
- id可以表示任何一個(gè)ObjC對(duì)象類型,類型后面的”<協(xié)議名>“用于約束作為這個(gè)屬性的對(duì)象必須實(shí)現(xiàn)該協(xié)議(注意:使用id定義的對(duì)象類型不需要加“*”);
- YHPerson作為事件觸發(fā)者,它實(shí)現(xiàn)了YHBoss代理(在ObjC中沒有命名空間和包的概念,通常通過前綴進(jìn)行類的劃分,“YH”是我們自定義的前綴);
- 在.h文件中如果使用了另一個(gè)文件的類或協(xié)議我們可以通過@class或者@protocol進(jìn)行聲明,而不必導(dǎo)入這個(gè)文件,這樣可以提高編譯效率(注意有些情況必須使用@class或@protocol),但是在.m文件中則必須導(dǎo)入對(duì)應(yīng)的類聲明文件或協(xié)議文件(如果不導(dǎo)入雖然語法檢查可以通過但是編譯鏈接會(huì)報(bào)錯(cuò));
- 使用respondsToSelector方法可以判斷一個(gè)對(duì)象是否實(shí)現(xiàn)了某個(gè)方法(如果方法后面需要參數(shù),需要注意方法名不是”codeIOS”而是“codeIOS:”,冒號(hào)也是方法名的一部分);
- 在實(shí)際開發(fā)過程中, 協(xié)議代理的作用:
- 傳值(反向傳值)
- 回調(diào)
反向傳值###
- 使用協(xié)議代理完成傳值: 協(xié)議帶參數(shù)(委托將要傳得值, 通過協(xié)議方法的參數(shù)傳給代理)
場(chǎng)景: 上一級(jí)界面顯示下一級(jí)界面的內(nèi)容
分析: 下一級(jí)界面想要將自己的內(nèi)容顯示在上一級(jí)界面, 但是自己做不到, 需要上一級(jí)界面來幫他完成 - YHGreenInterface.h
#import <Foundation/Foundation.h>
@protocol GreenInterfaceDelegate <NSObject>
// 讓協(xié)議方法帶參傳值
/**傳遞的值*/
- (void) showAppointValue:(NSString *) value;
@end
/**綠色界面*/
@interface YHGreenView : NSObject
/**需要的代理*/
@property (nonatomic, weak) id <GreenInterfaceDelegate> delegate;
/**傳遞需要顯示的數(shù)據(jù)*/
- (void) deliverValue:(NSString *) value;
@end
- YHGreenInterface.m
#import "YHGreenView.h"
@implementation YHGreenView
- (void) deliverValue:(NSString *) value {
if ([self.delegate respondsToSelector:@selector(showAppointValue:)]) {
[self.delegate showAppointValue:value];
}
else {
NSLog(@"無法傳值");
}
}
@end
- YHYellowInterface.h
#import <Foundation/Foundation.h>
#import "YHGreenView.h"
// 遵守協(xié)議, 實(shí)現(xiàn)協(xié)議方法
/**黃色界面*/
@interface YHYellowView : NSObject <GreenInterfaceDelegate>
@end
- YHYellowInterface.m
#import "YHYellowView.h"
@implementation YHYellowView
// 實(shí)現(xiàn)協(xié)議方法, 打印指定內(nèi)容
- (void) showAppointValue:(NSString *) value {
printf("顯示: %s", [value UTF8String]);
}
@end
- main.h
#import <Foundation/Foundation.h>
#import "YHYellowView.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 綠色界面委托
YHGreenView *GreenView = [[YHGreenView alloc] init];
// 黃色界面代理
YHYellowView *YellowView = [[YHYellowView alloc] init];
//將黃色界面設(shè)置為綠色界面的代理
GreenView.delegate = YellowView;
// 顯示輸入的內(nèi)容
printf("輸入要顯示的值:");
char a[100];
fgets(a, 101, stdin);
// 傳值
[GreenView deliverValue:[NSString stringWithUTF8String:]];
}
return 0;
}
回調(diào)###
- 協(xié)議代理回調(diào)作用: 通過協(xié)議方法的返回值, 將數(shù)據(jù)從代理傳給委托
場(chǎng)景: 顯示類想要得到從網(wǎng)上下載的數(shù)據(jù)
分析: 顯示類不能去下載數(shù)據(jù)(不是因?yàn)闆]能力, 而是不想去做), 需要一個(gè)下載類去下載數(shù)據(jù), 然后把數(shù)據(jù)給顯示類
三要素
委托: 顯示類(想要下載數(shù)據(jù))
協(xié)議: 下載數(shù)據(jù)
代理: 下載類
- YHShow.h
#import <Foundation/Foundation.h>
@protocol downloadDelegate <NSObject>
/**下載指定路徑下的數(shù)據(jù)*/
- (NSData *) downloadDataWithURL:(NSString *) urlStr;
@end
// 1. 委托
/**委托*/
@interface YHShow : NSObject
/**代理對(duì)象*/
@property (nonatomic, weak) id <downloadDelegate> delegate;
/**要求代理下載數(shù)據(jù)*/
- (void) needShow;
@end
- YHShow.m
#import "YHShow.h"
@implementation YHShow
- (void) needShow {
if ([self.delegate respondsToSelector:@selector(downloadDataWithURL:)]) {
NSData *data = [self.delegate downloadDataWithURL:@"http://blog.csdn.net/jingling/article/details/47753189"];
NSLog(@"顯示下載的數(shù)據(jù)%@", data);
}
}
@end
- YHDownload.h
#import <Foundation/Foundation.h>
#import "YHShow.h"
/**代理*/
@interface YHDownload : NSObject <downloadDelegate>
@end
- YHDownload.m
#import "YHDownload.h"
@implementation YHDownload
- (NSData *) downloadDataWithURL:(NSString *) urlStr {
// 獲取指定網(wǎng)絡(luò)路徑中的數(shù)據(jù)
// 創(chuàng)建統(tǒng)一資源定位符對(duì)象
NSURL *url = [NSURL URLWithString:urlStr];
NSData *data = [NSData dataWithContentsOfURL:url];
return data;
}
@end
- main.h
#import <Foundation/Foundation.h>
#import "YHDownload.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 1.創(chuàng)建一個(gè)顯示對(duì)象
YHShow *show = [[YHShow alloc] init];
// 2.創(chuàng)建一個(gè)下載對(duì)象
YHDownload *download = [[YHDownload alloc] init];
// 3.設(shè)置代理
show.delegate = download;
// 4.開始下載
[show needShow];
}
return 0;
}