<<Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法>>笔记-协议与分类

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

  如果要在委托对象上调用可选方法,那么必须提前使用类型信息查询方法判断这个委托对象能否响应相关选择子。

  if ( [_delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)]){

    [_delegate networkFetcher:self didReceiveData:data];

  }

  这段代码用“respondsToSelector:”来判断委托对象是否实现相关方法。如果实现了就调用,如果没实现,就不执行任何操作。

  delegate 对象中的方法名也一定要起得很恰当才行。方法名应该准确描述当前发生的事件以及 delegate 对象为何要获知此事件。

  如果委托方法多次调用,每次都检测委托对象是否能相应此选择子,那就显得多余了。可以在实例中嵌入一个含有位段的结构体作为其实例变量,而结构体中的每个位段则表示 delegate 对象是否实现了协议中的相关方法。

  @interface EOCNetworkFetcher () {

    struct {

      unsigned int didReceiveData : 1;

      unsigned int didFailWithError : 1;

      unsigned int didUpdateProgressTo : 1;

    } _delegateFlags;

  }

  这个结构体用来缓存委托对象是否能相应特定的选中子。实现缓存功能所用的代码可以写在 delegate 属性所对应的设置方法里:

  -(void)setDelegate:(id<EOCNetworkFetcher>)delegate{

    _delegate = delegate;

    _delegateFlags.didReceiveData = [delegate respondsToSelector:@selector(networkFetcher:didReceiveData:)];

    _delegateFlags.didFailWithError = [delegate respondsToSelector:@selector(networkFetcher:didFailWithError:)]; 

    _delegateFlags.didUpdateProgressTo = [delegate respondsToSelector:@selector(networkFetcher:didUpdateProgressTo:)];  

  }

  这样的话,每次调用 delegate 的相关方法前,就不用检测委托对象是否能相应给定的选择子了,而是直接查询结构体里的标准:

  if ( _delegateFlags.didUpdateProgressTo ){

    [_delegate networkFetcher:self didUpdateProgressTo:currentProgress]; 

  }

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

  将委托多选应该支持的接口定义成协议,在协议中把可能需要处理的事件定义成方法。

  当某对象需要从另外一个对象中获取数据时,可以使用委托模式。这种情况下,该模式称为“数据源协议”。

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

24、将类的实现代码分散到便于管理的数个分类之中

  类中经常容易填满各种方法,而这些方法的代码则全部堆在一个巨大的实现文件里。有时这么做是合理的,因为即便通过重构把这个类打散,效果也不会更好。在此情况下,可以通过 Objective-C 的“分类”机制,把类代码按逻辑划分入几个分区中,这对开发与调试都有好处。

  使用分类机制把类的实现代码划分成易于管理的小块。

  将应该视为“私有”的方法归入名叫 Private 的分类中,以隐藏实现细节。

25、总是为第三方类的分类名加前缀

  向第三方类中添加分类时,总应该给其名称加上你专用的前缀。

  向第三方类添加分类时,总应给其中的方法名加上你专用的前缀。

26、勿在分类中声明属性

  属性是分装数据的方式。尽管从技术上说,分类里也可以声明属性,但这种做法还是要尽量避免。原因在于,除了“class-continuation 分类”之外,其他分类都无法向类中新增实例变量,因此,他们无法把实现属性所需要的实例变量合成出来。

  把封装数据所用的全部属性都定义在主接口里。

  在“class-continuation 分类”之外的其他分类中,可以定义存取方法,但尽量不要定义属性。

27、使用“class-continuation 分类”隐藏实现细节

  通过“class-continuation 分类”向类中新增实例变量。

  如果某属性在主接口中声明为“只读”,而类的内部又要用设置方法修改此属性,那么久在“class-continuation 分类”中将其扩展为“可读写”。

  把私有方法的原型声明在“class-continuation 分类”里面。

  若想使类所遵循的协议不为人所知,则可于“class-continuation 分类”中声明。

28、通过协议提供匿名对象

  协议可在某种程度上提供匿名类型。具体的对象类型可以淡化成遵从某协议的 id 类型,协议里规定了对象所应实现的方法。

  使用匿名对象来隐藏类型名称(或类名);

  如果具体类型不重要,中要的是对象能够相应(定义在协议里的)特定方法,那么可使用匿名对象来表示。

posted @ 2017-07-27 11:37  晚安早安  阅读(113)  评论(0编辑  收藏  举报