需要了解ios协议, 首先看一个代码示例:
- 流氓协议(YHBadManDelegate.h)
#import <Foundation/Foundation.h>
/**流氓协议*/
@protocol BadManDelegate <NSObject>
@required // 必须实现的方法
/**吃*/
- (void) eat;
/**骗*/
- (void) lie;
@optional // 可选实现的方法
- (void) drink;
@end
- 君子协议(GentlemanDelegate.h)
/**君子协议*/
@protocol GentlemanDelegate <NSObject>
// 协议内容只能有方法不能有属性
// 协议方法
/**动口不动手*/
- (void) fight;
/**爱钱取之有道*/
- (void) loveMoney;
@end
- 初始化遵守协议的对象
#import <Foundation/Foundation.h>
#import "BadManDelegate.h"
#import "GentlemanDelegate.h"
// 遵守协议的类就是代理类; 如果一个类遵守了协议, 就要去实现协议方法;
/**遵守流氓协议的代理*/
// 一个类可以同时遵守多个协议, 在一个<>中多个协议名用逗号隔开
@interface YHPerson : NSObject <BadManDelegate, GentlemanDelegate>
@end
@interface YHStudent : NSObject <BadManDelegate>
- (void) study;
@end
- 实现协议
#import "YHPerson.h"
@implementation YHPerson
- (void) eat {
NSLog(@"正在吃霸王餐!!");
}
- (void) lie {
NSLog(@"在撒谎!!");
}
- (void) fight {
NSLog(@"动口不动手!!");
}
- (void) loveMoney {
NSLog(@"爱钱取之有道!!");
}
@end
@implementation YHStudent
// 实现学生相关的方法
- (void) study {
NSLog(@"Good Good Study, Day Day Up.");
}
// 实现流氓协议的方法
- (void) eat {
NSLog(@"吃完带抢");
}
- (void) lie {
NSLog(@"处处留情!!");
}
@end
这里说明几点:
- 一个协议可以扩展自另一个协议,例如上面BadManDelegate就扩展自NSObject,如果需要扩展多个协议中间使用逗号分隔;
- 和其他高级语言中接口不同的是协议中定义的方法不一定是必须实现的,我们可以通过关键字进行@required和@optional进行设置,如果不设置则默认是@required(注意ObjC是弱语法,即使不实现必选方法编译运行也不会报错);
- 协议通过<>进行实现,一个类可以同时实现多个协议,中间通过逗号分隔;
- 协议的实现只能在类的声明上,不能放到类的实现上(也就是说必须写成@interface YHPerson:NSObject <AnimalDelegate>而不能写成@implementation YHPerson<AnimalDelegate>);
- 协议中不能定义属性、成员变量等,只能定义方法;
由上例可以看出,iOS中的协议其实和生活中的协议基本上是一样的,比如生活中签订的就业协议、保密协议以及一些合同等等。而协议本身就是一系列的条款及规定(在OC中的协议主要看的是甲方对乙方指定的规定)。
-
协议的基本概念
- 委托: 即签订协议时的甲方(指定协议)
- 代理: 即签订协议时的乙方(遵守协议)
- 协议: 甲方对乙方的规定、要求(OC中的实质就是一系列的方法)
-
协议的特点
- 一个类可以同时遵守多个协议(遵守协议后必须实现协议方法)
- 同一个协议可以被多个类遵守, 不同的类中协议方法可以有不同的实现
-
协议的主要要求
遵守协议就是要做到协议上规定的内容, 遵守什么样的协议就需要做什么样的对象例如:
1、君子协议
协议内容: 君子动口不动手、君子爱财取之有道、君子爱美取只有礼等
君子: 遵守君子协议的人
2、流氓协议
协议内容: 吃喝嫖赌、坑蒙拐骗偷等
流氓: 遵守流氓协议的人
- 使用协议代理解决问题需要找到三要素(协议、代理、委托)
- 委托: 老板 (想要做某件事情, 但是自己没有能力去做, 需要别人来帮他完成)
- 协议: 会iOS开发 (委托对代理的要求, 委托想要代理帮他做的事情)
- 代理: 遵守协议的对象 (实际做事情的对象)
使用协议代理解决问题: (如果一个对象想要做一件事情(完成一个功能), 但是自己做不到, 需要一个可以做到的对象来帮他完成, 考虑使用协议代理)
场景: 老板想要做一个iOS项目
分析: 老板想做iOS项目, 但是自己不会做, 找一个会iOS开发的人来帮他做
- YHBoss.h
#import <Foundation/Foundation.h>
//2.协议
/**声明协议*/
@protocol StaffDelegate <NSObject>
/**会IOS开发(做开发)*/
- (void) codeIOS;
@end
// 1. 委托
// 委托需要一个遵守协议的对象来帮他做事情 (委托需要一个代理)
/**委托类(制定协议)*/
@interface YHBoss : NSObject
// 任何遵守协议的类创建的对象都可以作为老板的代理
// 注意: delegate要用weak修饰(防止循环引用造成对象不能销毁)
/**代理*/
@property (nonatomic, weak) id <StaffDelegate> delegate;
// 告诉代理何时去做事情
/**告诉代理*/
- (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.代理(遵守协议, 实现协议方法)
/**代理*/
@interface YHPerson : NSObject <StaffDelegate>
@end
- YHPerson.m
#import "YHPerson.h"
#import "YHBoss.h"
@implementation YHPerson
// 判断一个对象是否实现了某个方法
// (这里判断self.delegate是否实现了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.首先需要一个boss
YHBoss *boss = [[YHBoss alloc] init];
// 2.需要一个员工
YHPerson *person = [[YHPerson alloc] init];
// 3.让员工成为老板的代理
boss.delegate = person;
// 4.老板喊开工
[boss askStaffWorking];
}
return 0;
}
- id可以表示任何一个ObjC对象类型,类型后面的”<协议名>“用于约束作为这个属性的对象必须实现该协议(注意:使用id定义的对象类型不需要加“*”);
- YHPerson作为事件触发者,它实现了YHBoss代理(在ObjC中没有命名空间和包的概念,通常通过前缀进行类的划分,“YH”是我们自定义的前缀);
- 在.h文件中如果使用了另一个文件的类或协议我们可以通过@class或者@protocol进行声明,而不必导入这个文件,这样可以提高编译效率(注意有些情况必须使用@class或@protocol),但是在.m文件中则必须导入对应的类声明文件或协议文件(如果不导入虽然语法检查可以通过但是编译链接会报错);
- 使用respondsToSelector方法可以判断一个对象是否实现了某个方法(如果方法后面需要参数,需要注意方法名不是”codeIOS”而是“codeIOS:”,冒号也是方法名的一部分);
- 在实际开发过程中, 协议代理的作用:
- 传值(反向传值)
- 回调
反向传值###
- 使用协议代理完成传值: 协议带参数(委托将要传得值, 通过协议方法的参数传给代理)
场景: 上一级界面显示下一级界面的内容
分析: 下一级界面想要将自己的内容显示在上一级界面, 但是自己做不到, 需要上一级界面来帮他完成 - YHGreenInterface.h
#import <Foundation/Foundation.h>
@protocol GreenInterfaceDelegate <NSObject>
// 让协议方法带参传值
/**传递的值*/
- (void) showAppointValue:(NSString *) value;
@end
/**绿色界面*/
@interface YHGreenView : NSObject
/**需要的代理*/
@property (nonatomic, weak) id <GreenInterfaceDelegate> delegate;
/**传递需要显示的数据*/
- (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"
// 遵守协议, 实现协议方法
/**黄色界面*/
@interface YHYellowView : NSObject <GreenInterfaceDelegate>
@end
- YHYellowInterface.m
#import "YHYellowView.h"
@implementation YHYellowView
// 实现协议方法, 打印指定内容
- (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];
//将黄色界面设置为绿色界面的代理
GreenView.delegate = YellowView;
// 显示输入的内容
printf("输入要显示的值:");
char a[100];
fgets(a, 101, stdin);
// 传值
[GreenView deliverValue:[NSString stringWithUTF8String:]];
}
return 0;
}
回调###
- 协议代理回调作用: 通过协议方法的返回值, 将数据从代理传给委托
场景: 显示类想要得到从网上下载的数据
分析: 显示类不能去下载数据(不是因为没能力, 而是不想去做), 需要一个下载类去下载数据, 然后把数据给显示类
三要素
委托: 显示类(想要下载数据)
协议: 下载数据
代理: 下载类
- YHShow.h
#import <Foundation/Foundation.h>
@protocol downloadDelegate <NSObject>
/**下载指定路径下的数据*/
- (NSData *) downloadDataWithURL:(NSString *) urlStr;
@end
// 1. 委托
/**委托*/
@interface YHShow : NSObject
/**代理对象*/
@property (nonatomic, weak) id <downloadDelegate> delegate;
/**要求代理下载数据*/
- (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(@"显示下载的数据%@", 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 {
// 获取指定网络路径中的数据
// 创建统一资源定位符对象
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.创建一个显示对象
YHShow *show = [[YHShow alloc] init];
// 2.创建一个下载对象
YHDownload *download = [[YHDownload alloc] init];
// 3.设置代理
show.delegate = download;
// 4.开始下载
[show needShow];
}
return 0;
}