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

“委托模式”/“代理模式”(Delegate pattern)主旨:

​ 定义一套接口,其他对象若想接收当前对象的委托,则需遵从此接口成为其“委托对象”(delegate)。而当前对象则可以给其委托对象传递一些信息,也可以在放生相关事件时通知委托对象。(此模式可将数据与业务逻辑解耦)

​ 通常情况下delegate对象会持有当前对象,所以需要将delegate属性定义成weak,否则会造成循环引用导致内存泄露。

​ 若要向外界公布此类实现了某协议,那么就在接口(.h文件)中声明;而如果这个协议是个委托协议的话,就可以在类内部(class-continauation分类中)声明。

​ 委托协议中的方法一般都是“可选的”(用@optional声明,后面的都是可选),因为代理未必关心其中的所有方法。

​ 在调用delegate中的方法时,总是应该把当前对象也一并传入方法中,这样delegate在实现相关方法时,就能根据传入的实例分别执行不同的代码了。如:

- (void)networkFetcher:(NetworkFetcher *)fetcher 
              didReceiveDate:(NSData *)data {
  if (fetcher == _myFetcherA) {
  } else if (fetcher == _myFetcherB) {
  }
}

​ 可以在当前对象中声明一个含有位段的结构体为其实例对象,结构体中的每个位段表示delegate是否实现了协议中的相关方法:

@interface NetworkFetcher () {
  struct {
    unsigned int didReceiveData : 1;
    unsigned int didFailWithError : 1;
    unsigned int didUpdateProgressTo : 1;
  } _delegateFlages; // 实例对象!!!
}
// 设置代理时,就缓存当前delegate是否能响应协议中的相关方法
- (void)setDelegate:(id< NetworkFetcher>)delegate {
  _delegate = delegate;
  _delegateFlages.didReceiveData = [delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];
  ....
}

​ 协议方法要调用很多次时,值得进行这种优化。而是否需要优化,则应依照具体代码来定。这种需要分析代码性能,并找出瓶颈,若发现执行速度需要改进,则可使用此技巧。

要点:

  • 委托模式为对象提供了一套接口,使其可由此将相关事件告知其他对象

  • 将委托对象应该支持的接口定义成协议,在协议中把可能需要处理的时间定义成方法

  • 当某对象需要从另外一个对象中获取数据时,可使用委托模式。这种情境下,该模式亦称“数据源协议”(data source protocal)

  • 若有必要,可实现含有段位的结构体,将委托对象是否能响应相关协议方法这一信息缓存至其中

Last updated

Was this helpful?