Objective-C语言特性:协议(protocol),它与Java的“接口”(interface)类似。
Objective-C不支持多继承,但可以把类的实现方法定义在协议里面。
协议最为常见的用途是实现委托模式(Delegate pattern)。
委托模式(Delegate pattern):
用来实现对象间的通信,
该模式的主旨是:定义一套接口,某对象若想授受另一个对象的委托,则需遵从此接口,以便成为其“委托对象”(delegate)。而这“另一对象”则可以给其委托对象回传一些消息,也可以在发生相关事件时通知委托对象。
此模式可以将数据与业务逻辑解耦。
由数据源(data source)与委托(delegate)对象分别处理。
数据源:数据源流向类(输入),
委托:从类流向受委托者(输出)。
数据源和受委托者可以是两个不同的对象。然而一般情况下,都用同一个对象来扮演这两种角色。
委托协议命名:
类名+Delegate(后缀)
有了协议后,类就可以用一个属性来存放其委托对象了。
例:
@property(nonatomic, weak) id<类名+Delgate> delegate;
// 此处用weak表示“百拥有关系”(nonowning relationship)。
// 还可以用unsafe_unretained。
// weak与unsafe_unretained的区别:如果需要在相关对象销毁时自动清空(autoniling,参见第6条),则用weak。反之用unsafe_unretained。
@optional关键字(可选的):
在委托对象上调用可选方法时必须提前使用类型信息查询方法(参见第14条)来判断这个委托对象能否响应相关选择子。
例:if([_delegate respondsToSelector:@selector(委托方法)]) {
[_delegate 委托方法];
}
如果非可选方法,则不需要。
关于选择子判断的优化:
有时除了第一次检测的结果有用之外,后续的检测可能是多余的。对于频繁的检测,也消耗性能。
对此可以优化:把委托对象能否响应某个协议方法这一信息缓存起来。
位段:
将方法响应能力缓存起来的最佳人途径是使用“位段”(bitfield)数据类型。这是一项无人问津的C语言特性。
把结构体中某个字段所占用的二进制位个数设为特定的值。
例:struct data {
unsigned int fieldA: 8; // 表示0~255之间的值
unsigned int fieldB: 4;
unsigned int fieldB: 1; // 表示0或1
}
这样就可以嵌入一个含有位段的结构体作为实例变量,而结构体中的每个位段表示delegate对象是否实现了协议中的相关方法。(类似字典)
例:struct {
unsigned int didReceiveData: 1;
unsigned int didFailWithError: 1;
unsigned int didUpdateProgressTo: 1;
} _delegateFlags;
-(void)setDelegate:(id<协议> delegate){
_delegate = delegate;
_delegate.didReceiveData = [@delegate respondsToSelector:@selector(方法)]; // 值为:0或1
// ……
}
if(_delegate.didReceiveData) {
[_delegate 方法]
}
delegate对象可以有多个,所以在定义或调用时,应该把发起委托的类或实例加入进去。
例:- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if(tableView == tableViewA){
}else if(tableView == tableViewA){
}
}