第23条:通过委托与数据源协议进行对象间通信

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){

  }

}

原文地址:https://www.cnblogs.com/Pikdays/p/5739786.html