protocol(协议)是一组公开接口的集合,任何类都可以实现这一组接口。
协议的声明
@protocol testProtocol
@required
- (void)requiredMethod;
@optional
- (BOOL)optionalMethod;
@end
在objective-c中,我们通过@protocol关键字来声明一个协议,在协议中我们可以声明需要的方法提供给遵守协议的类。协议中的方法有2种类型如下:
- @required :遵守该协议的类必须实现此关键字下的所有方法。
- @optional :遵守该协议的类可以选择实现此关键字下的方法,也可以都不实现。默认情况下协议中的方法都是这种类型的。
遵循一个协议
在声明后面添加尖括号<协议名>来让某个类遵循某个协议
@interface ClassA : NSObject<testProtocol>
@end
协议的特点
协议的应用
1.约束对象
在开发中,我们经常会遇到这样一种情况,我们希望使用到的实例对象必须拥有一些功能。这个时候我们可以要求这个实例对象的类必须遵守指定的协议。
//定义一个协议
@protocol isProtocol
@required
-(void)printSome;
@end
@interface ViewController ()
//需要一个遵循了isProtocol协议的对象
@property (nonatomic, strong) id<isProtocol> obj;
@end
这样写的好处在于增加了代码的可读性,让开发人员一眼就明白这个对象需要满足什么条件。然后我们定义一个类,这个类遵循isProtocol这个协议,并实现协议中的方法
@interface ClassA : NSObject<isProtocol>
@end
@implementation ClassA
- (void)printSome {
NSLog(@"do protocol method");
}
@end
在viewController中调用
self.obj = [[ClassA alloc] init];
[self.obj printSome]
2.多重继承
面向对象编程语言中的多重继承指的是一个类可以同时继承多个父类的行为和特征功能。单一继承是指:一个子类只继承一个父类。
从上面的例子我们可以看出,遵从了协议的对象可以调用协议中提供的方法,不需要知道对象的具体类型。也就是说只要是遵从了协议的类都可以对协议中提供的方法进行不同的实现。并且一个类可以遵守多个协议!
例如,人类只能奔跑,是不能飞行和游泳的。但我们希望人类可以继承鸟和鱼的特性,让人类也可以飞行和游泳。
//定义鸟和鱼的协议
@protocol birdProtocol
@required
-(void)canFlying;
@end
@protocol fishProtocol
@required
-(void)canSwiming;
@end
//定义人的类,让人类遵循鸟和鱼这两个协议
@interface Person : NSObject<birdProtocol, fishProtocol>
//人本身只会奔跑
- (void)canRunning;
@end
但遵循鸟和鱼的协议后,人就可以实现鸟和鱼协议中提供的方法,拥有飞翔和游泳的能力。
@implementation Person
- (void)canRunning {
NSLog(@"i can running");
}
- (void)canFlying {
NSLog(@"i can fly");
}
- (void)canSwiming {
NSLog(@"i can swim");
}
@end
//这样的人就可以同时拥有自己和其他协议提供的能力了。
Person *person = [[Person alloc] init];
[person canRunning];
[person canFlying];
[person canSwiming];
3.代理,传值
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
在开发中,我们可能遇到这样一种情况,某个类的实例希望实现一个功能,但这个功能和这个实例并没有什么关系。这个时候就需要委托一个具有相关职能的类的实例来代理实现这个工作,并可以把功能中得到的结果告诉自己。
例如:一个老板想开店赚钱,但老板并不应该亲自洗完,收钱。所以老板需要请一个会洗完和收银的员工来帮他工作。
@protocol employeesProtocol
//洗碗
- (void)Washing;
//收银
- (NSInteger)Cashier;
@end
首先我们需要一个协议来限制员工必须会洗完和收银。
@interface Employees : NSObject<employeesProtocol>
@end
@implementation Employees
-(void)Washing {
NSLog(@"working");
}
-(NSInteger)Cashier {
return 100;
}
@end
@interface Boss : NSObject
@property (nonatomic, strong) id<employeesProtocol> employee;
@property (nonatomic, assign) NSInteger assets;
- (void)letEmployeeWorking;
@end
@implementation Boss
- (void)letEmployeeWorking {
[self.employee Washing];
self.assets += [self.employee Cashier];
}
@end
定义员工类,遵循员工协议。并实现协议中提供的方法。定义老板类,包含一个遵循员工协议的对象和一个变量表示当前的资产。老板可以让员工工作,员工洗完,收银并把赚来的钱交给老板
id<employeesProtocol> employee = [[Employees alloc] init];
Boss *boss = [[Boss alloc] init];
boss.delegate = employee;
[boss letEmployeeWorking];
使用的时候,我们只需要设置boss的代理,并且开始干活就可以了。于是每当boss让员工干活就会触发员工协议中的方法。可以参考tableview的点击操作,每当tableview点击以后,就会通知代理,我被点击了你可以开始处理这个事件了。
4.回调
回调是建立在代理之上的,当我们想把事件或数据回调给某个对象,我们可以把这个对象设置为自己的代理。这样我们就可以通过调用协议提供的方法把事件或数据传递给代理了。
最简单的例子:我们有A,B两个viewcontroller,A->B,当B加载后将这个信息告诉A。
@protocol callbackProtocol <NSObject>
- (void)callBackWith:(NSString *)msg;
@end
@interface NextViewController : UIViewController
@property (nonatomic, weak) id<callbackProtocol> delegate;
@end
@implementation NextViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.delegate callBackWith:@"viewDidLoad"];
}
@end
先定义B控制器,B控制器提供一个回调协议,并包含一个遵循这个回调协议的代理对象,当load时,执行代理提供的方法。
@interface ViewController ()<callbackProtocol>
@end
//实现协议中的方法
- (void)callBackWith:(NSString *)msg {
NSLog(@"%@",msg);
}
NextViewController *vc = [[NextViewController alloc] init];
vc.delegate = self;
[self.navigationController pushViewController:vc animated:YES];
而界面A遵循B中的回调协议,初始化控制器B,并设置自己为B中的代理对象。这样当B执行viewdidload的时候就会执行代理,告诉A控制器自己正在viewDidLoad。即把初始化这个事件和信息回调给A控制器了。