Effective objective C 2.0笔记(三)

第三章 接口与API设计

第15条:用前缀避免命名冲突

  • OC没有命名空间,为了避免潜在的命名冲突,可以使用加前缀的方式
  • 选择公司,应用程序或有关联的名称作为类名的前缀,并在所有代码中使用这一前缀

    第16条:提供“全能初始化方法”

  • 全能初始化方法:为对象提供必要信息以便其能完成工作的初始化方法,类似UITableViewCell初始化方法: ```
  • (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier ``` 这里必要信息是:style,reuseIdentifier样式及重用标识
  • 有多个初始化方法时,可以在其中选定一个作为全能初始化方法,令其他初始化方法都调用他。这样,这有全能初始化方法存储内部数据,需要改变内部结构时,只需要改全能初始化方法而不用改动其他初始化方法
  • 如果超类的初始化方法不适用于子类,那么应该覆写这个超类的方法,并在其中抛出异常 ##第 17条:实现description方法 通过NSLog打印并查看对象信息时,对象会收到description消息,返回对象相关的信息。但默认的description方法返回的信息,有时并不是我们想要的,通过覆写description可以实现输出我们在定义的信息。类似的,还有debugDescription方法,它和description区别:debugDescription方法是开发者在调试器以控制台命令打印对象时调用的(LLDB “po”命令)。当我们通过LLDB “po”命令打印对象信息时,就可以覆写debugDescription返回我们需要的信息。

    第18条:尽量使用不可变对象

  • 使用属性时,默认情况下属性是“可读可写”的,这样设计出来的类都是“可变的”。
  • 为了防止对象被更改,应该尽量把对外公布的属性设为只读,而只在必要的时候才对外公布。
  • 若某属性仅可于对象内部修改,可以在分类中将readonly属性扩展为readwrite属性。
  • 不要把可变的集合(collection)作为属性公开,而应提供方法,通过方法修改对象的可变collection。

    第19条:使用清晰而协调的命名方式

  • 方法命名:方法名使用“驼峰大小写命名法”;使用“in”,“for”,“with”等介词连接,使得代码读起来和句子一样;方法名要明确每个参数等含义,把表示参数类型的名词放在参数前面;方法有返回值时,方法名的首个词最好是返回值的类型;布尔属性应该根据其功能,选用类似has, is当前缀;不要使用类似str简称,应该使用全称;方法名也不能长得太过分,应尽量在用意表达清楚的基础上做到言简意赅;
  • 类和协议的命名:类和协议的名称要加上前缀,避免命名冲突;命名应该把词汇组织好,从左至右读起来通顺;定义委托协议时,把委托接口的类名放在前面,后面加Delegate一词。

    第20条:为私有方法名加前缀

    为私有方法名加前缀,很容易区分公共方法和私有方法,有助于调试。使用何种前缀,由个人喜好决定,一般用p_作为前缀,尽量不要单独使用_作为前缀只是预留给苹果爸爸的。

    第21条:理解错误模型

    1. 用异常机制处理错误
  • 通过@throw抛出异常(NSException)
  • 通过@try @catch捕获并处理异常

但这种机制,如果抛出异常,那么本应在作用域末尾释放的对象不会自动释放,也就是说默认情况下不是“异常安全的”;所以,异常只应该应用于极其严重的错误,异常抛出后无须考虑恢复问题,而且应用程序此时应该退出。

  1. NSError
    • 处理不是很严重的错误,表明有错误发生,程序不用退出。
    • 用法灵活,对象里封装了3条消息:Error domain错误范围;Error code错误码;Userinfo用户信息;
    • NSError一个常见用法是通过委托协议传递此错误。 ```
    • (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; ```
    • 另一个用法是经由方法的输出参数返回调用者,传递的参数是个指针,这个指针又指向另一个指针,另一个指针指向NSError对象。 ```
    • (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(nullable NSDictionary<NSFileAttributeKey, id> *)attributes error:(NSError **)error ```

      第22条:理解NSCopying协议

    • 若想令自己所写的对象具有拷贝功能(copy),需要实现NSCoping协议。通过实现- (id)copyWithZone:(NSZone *)zone方法返回新的对象
    • 如果自定义的类分为可变和不可变版本,要同时实现NSCopying和NSMutableCopying协议

第四章 协议与分类

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

  • 委托模式(代理模式)是一种实现对象间通信的设计模式,可将数据与业务逻辑解耦;主旨是定义一套接口,某一对象想接受另一对象的委托,需遵循此协议,成为其代理;另一对象可以给委托对象回传消息;
  • 委托协议名通常是相关类名后加Delegate,方便理解;
  • 委托协议的方法默认是@require的,使用@optional可以指明可选方法;委托对象调用可选方法,必须提前使用类型信息查询方法判断是否响应选择器:respondsToSelector:
  • 定义委托协议方法时,应该提供一个委托发起对象的实例作为参数,方便根据该实例分别执行不同的代码;

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

  • 一个类的方法过多时会变得难于管理,可以使用分类把类的实现代码划分成便于管理的小块;
  • 将不想公开的方法归入单独一个分类中,隐藏实现细节;

    第25条:总是为第三方类的分类名称加前缀

    第26条:勿在分类中声明属性

  • 除了Extension外,其他分类都无法向类中新增实例变量,因此无法把属性所需的实例变量合成出来;
  • 可以通过关联对象技术解决分类中不能合成实例变量的问题,实现为分类添加属性,这样做在内存管理问题上容易出错,应该尽量避免
  • 有时只读属性还是可以在分类中使用,实现属性getter方法,就不会为该属性合成实例变量了;(类似于swift中计算属性的使用)

    第27条:使用class-continuation分类隐藏实现细节

    class-continuation分类即Extension

  • 可以通过Extension为类添加属性,Extension定义在原类的实现文件中
  • 可以将“私有”的属性声明在Extension里面,这样外界既不能访问该属性也完全不知道这个属性,从而隐藏相关细节
  • 类所遵循协议也可以在Extension中声明,从而使协议也不为外界所知
  • 如果属性在.h文件声明为readonly,而类的内部又要改动该属性,可以在Extension中将属性声明为readwrite

    第28条:通过协议提供匿名对象

    匿名对象:协议可以提供匿名类型:遵从该协议的纯id类型,如委托对象delegate

  • 需要隐藏类型名称,可以使用匿名对象;
  • 如果具体类型不重要,只要对象能响应协议的方法,也可以使用匿名对象;
Written on March 24, 2019