前言

Effective Objective-C 读书笔记 - 接口与API设计

笔记

用前缀避免命名空间冲突

  1. 前缀字母至少3个,两字母的前缀被Apple保留
  2. 注意:实现文件中的纯C函数以及全局变量也最好要加前缀,因为他们也是全局可见的。纯C函数,默认是extern的。(PS 见参考1)

提供全能初始化方法

  1. 初始化方法以 init 开头。

  2. 如果一个类有多个初始化方法的话,最好要选定一个方法为全能初始化方法,让其他的初始化方法都来调用这个全能初始化方法。

  3. 在全能初始化方法中,才执行数据的存储等等操作;其他方法只是改变调用全能初始化方法的参数而已。这样简单地保证了所有的初始化方法都能正确执行。

  4. 全能初始化方法要链式调用:也就是说,子类的全能初始化方法要调用超类的全能初始化方法。

  5. 还有子类的全能初始化方法如果与超类的全能初始化方法不重名的话,要覆写该方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // 超类全能初始化方法(矩形类)
    - (id)initWithWidth:(float)width andHeight:(float)height {
    if (self = [super init]) {
    _width = width;
    _height = height;
    }
    return self;
    }

    // 子类全能初始化方法(正方形类)
    - (id)initWithDimension:(float)dimension {
    if (self = [super initWithWidth:dimension andHeight:dimension]) { // 全能初始化方法链式调用

    }
    return self;
    }

    // 覆写超类方法
    - (id)initWithWidth:(float)width andHeight:(float)height {
    float dimension = MAX(width, height);
    return [self initWithDimension:dimension];
    }

    这样保证了:

    1. 子类调用自己的任何初始化方法,都最终会调用自己的全能初始化方法
    2. 子类调用超类的任何初始化方法,最终会调用超类的全能初始化方法;但是该方法被覆写,而且覆写时调用了子类自己的全能初始化方法。所以最终还是调用了子类自己的全能初始化方法~~

实现description方法

  1. 方便调试
  2. 除了你想看到的信息之外,还是要将默认的description的信息打印出来:也就是类名字和指针地址
  3. 注意NSObject协议中的debugDescription方法,该方法只在 开发者在控制台中打印对象时 才会被调用。它的默认实现是直接调用 description 方法。在LLDB控制台输入 po object 可以打印object对象

尽量使用不可变对象

  1. 尽量将对外的属性设置为readonly
  2. 可以在实现文件里面,将属性重新定义成readwrite

使用清晰而协调的命名方式

为私有方法加前缀

  1. 例如 - (void)p_privateMethod;

理解Objective-C错误模型

  1. ARC不是异常安全的,也就是说:如果抛出异常,那么本应在作用域末尾释放的对象现在却不会自动释放了。

  2. 基于上述原因,OC代码只会在极其严重的错误发生时,才抛出异常;而且此时应该结束app运行。

  3. 除了抛出异常(NSException)之外,还可以使用稍微缓和的方法,也就是NSError 。用法如下:

    1
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;

    会将错误传到回调delegate中

理解NSCopying协议

  1. 要让自定义的类的对象,具有拷贝功能,也就是具有正确的[object copy]; 方法,该类就必须实现NSCopying协议的 - (id)copyWithZone:(NSZone *)zone 方法。(PS 不需要管zone参数)

  2. copy方法定义在NSObject里面,所以所有类都继承了该方法。该方法的默认实现是简单的调用 copyWithZone: 方法

  3. 我们只需要实现类的copyWithZone: 方法,然后调用对象的copy方法,就可以实现对象的拷贝。(PS 要先声明该类遵循NSCopying协议)

  4. 可以使用 -> 访问实例变量,而不是属性。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @implementation EOCPerson {
    NSMutableSet *_friends; // 实例变量,不是属性
    }

    - (id)copyWithZone:(NSZone *)zone {
    EOCPerson *copy = [[self class] allocWithZone:zone] init];
    copy->_friends = [_friends mutableCopy]; // -> 访问实例变量
    return copy;
    }

    @end
  5. 深拷贝和浅拷贝

    1. 深拷贝:对象里面的底层数据也一并拷贝
    2. 浅拷贝:只拷贝对象,对象里面的底层数据公用一份
    3. Foundation框架的collection类(NSArray, NSSet…)的默认拷贝方法都是浅拷贝

参考