1.协议基本概念
什么是协议?
- 其他语言有接口的概念,接口就是一堆方法的声明没有实现.
- OC中没有接口的概念,OC中的接口就是协议.
- 协议Protocol是由一系列的方法声明组成的
书写协议的格式?
格式:
@protocol 协议名称// 方法声明列表@end
一个类怎么遵循协议?
类遵守协议格式:
@interface 类名 : 父类 <协议名称1, 协议名称2,…>
@end
注意:
- 一个类可以遵守1个或多个协议
- 任何类只要遵守了Protocol,就相当于拥有了Protocol的所有方法声明
协议和继承区别
- 继承之后默认就有实现, 而protocol只有声明没有实现
- 相同类型的类可以使用继承, 但是不同类型的类只能使用protocol
- protocol可以用于存储方法的声明, 可以将多个类中共同的方法抽取出来, 以后让这些类遵守协议即可
2.协议注意事项
什么是基协议?
- 基协议:是基协议,是最根本最基本的协议,其中声明了很多最基本的方法。
- 注意:建议每个新的协议都要遵守NSObject协议
协议有哪些注意事项?
- 协议只能声明方法, 不能声明属性
- 父类遵守了某个协议, 那么子类也会自动遵守这个协议
- 在OC中一个类可以遵守1个或多个协议 注意: OC中的类只能有一个父类, 也就是说OC只有单继承
- OC中的协议又可以遵守其它协议, 只要一个协议遵守了其它协议, 那么这个协议中就会自动包含其它协议的声明
协议中控制方法的能否实现的关键字是什么?各有什么作用?
- 注意: 如果没有使用任何关键字修饰协议中的方法, 那么该方法默认就是required的
- 注意: @required和@optional仅仅使用程序员之间交流, 并不能严格的控制某一个遵守该协议的类必须要实现该方法, 因为即便不是实现也不会报错, 只会报一个警告
- @required 如果协议中的方法是@required的, 要求遵守协议的类实现@required所修饰的方法,如果没有实现该方法, 那么会报一个警告
- @optional 如果协议中的方法是@optional的, 遵守协议的类可选择实现@optional所修饰的方法,如果没有实现该方法, 那么不会报警告
3.协议应用场景1-类型限定
问题1:什么是类型限定?
答:类型限定就是限定一个类必须遵守某个协议
问题2:类型限定的格式?
答: 数据类型<协议名称> 变量名
@property (nonatomic, strong) Wife*wife;
类型限定注意点
- 类型限定是写在数据类型的右边的
- 虽然在接受某一个对象的时候, 对这个对象进行了类型限定(限定它必须实现某个协议), 但是并不意味着这个对象就真正的实现了该方法. 所以每次在调用对象的协议方法时应该进行一次验证
if ([self.wife respondsToSelector:@selector(cooking)]) {[self.wife cooking];}
代理模式的应用场景?
1.当A对象想监听B对象的一些变化时, 可以使用代理设计模式 保姆想监听婴儿的变化, 那么保姆就可以成为婴儿的代理, 当婴儿发生变化之后保姆就可以监听到
2.当B对象发生一些事情, 想通知A对象的时候, 可以使用代理设计模式 婴儿想通知保姆, 那么就可以 让保姆成为婴儿的代理, 只要保姆成为婴儿的代理, 以后婴儿发生变化就可以通知保姆
3.当对象A无法处理某些行为的时候,想让对象B帮忙处理(让对象B成为对象A的代理对象) 婴儿无法自己吃东西, 也无法自己入睡, 所以可以让保姆帮忙处理. 只要让保姆成为婴儿的代理就可以帮婴儿喂它吃东西和哄他睡觉
用什么类型来接收遵守协议的代理对象?
使用id类型接收代理对象
// 如果使用id类型来接收保姆, 如果将来换保姆了, 婴儿类不用修改代码
@property (nonatomic, strong) idnanny;
问题3:实现代理的有哪几步?(保姆照顾婴儿 吃饭 睡觉)
答:
婴儿类中
1.声明婴儿是一个类(将当前对象传出去) @class Baby;
2.定义代理协议,协议中声明代理要帮婴儿做的事 (只声明方法,将婴儿传给代理,让代理实现协议中方法,注意协议格式)
@protocol BabyDelegate//喂婴儿吃饭- (void)eat:(Baby *)baby;//哄婴儿睡觉- (void)sleep:(Baby *)baby;@end
3.将代理作为属性,类型限定代理遵守协议
@property (nonatomic, weak) iddelegate;
4.声明方法,方法里调用代理,调用代理实现的协议方法,让代理帮婴儿吃饭,睡觉
//婴儿饿了要吃饭- (void)hurgry;//婴儿醒了要睡觉- (void)wake;
5.实现调用代理者的方法
@implementation Baby- (void)hurgry{// 6.判断代理是否实现了协议中的方法 if ([self.delegate respondsToSelector:@selector(eat:)]) { //7.如果代理实现了协议中的方法,就调用 [self.delegate eat:self]; }}- (void)wake{ if ([self.delegate respondsToSelector:@selector(sleep:)]) { [self.delegate sleep:self]; }}@end
代理类中
8.导入代理
@protocol BabyDelegate;
9.遵守代理
@interface Nurse : NSObject@end
10.实现协议中的方法,(喂婴儿,让婴儿吃饭,拿到婴儿才能给婴儿做事)
@implementation Nurse- (void)eat:(Baby *)baby{ baby.hurgryValue += 10; NSLog(@"喂婴儿吃饭!饥饿值:%lu", baby.hurgryValue);}- (void)sleep:(Baby *)baby{ baby.sleepValue += 5;NSLog(@"摇婴儿睡觉!疲劳值:%lu", baby.sleepValue);}@end
main函数中
int main(int argc, const char * argv[]) { @autoreleasepool {//11.创建所需对象 Baby *b = [[Baby alloc]init]; Nurse *n = [[Nurse alloc]init];//12.将代理对象作为接受代理者的代理 //(让保姆作为婴儿的代理) b.delegate = n;//设定婴儿初始饥饿值,疲劳值 b.hurgryValue = -5; b.sleepValue = -5;//13.接受代理者调用代理者的方法 //(婴儿饿了,醒了,需要吃饭和哄一哄) [b hurgry]; [b wake]; } return 0;}
5.代理设计模式练习及规范
协议的编写规范
- 一般情况下, 当前协议属于谁, 我们就将协议定义到谁的头文件中
- 协议的名称一般以它属于的那个类的类名开头, 后面跟上protocol或者delegate
- 协议中的方法名称一般以协议的名称protocol之前的作为开头
- 一般情况下协议中的方法会将触发该协议的对象传递出去
- 一般情况下一个类中的代理属于的名称叫做 delegate
- 当某一个类要成为另外一个类的代理的时候, 一般情况下在.h中用@protocol 协议名称;告诉当前类 这是一个协议. 在.m中用#import真正的导入一个协议的声明