OC读书笔记

熟悉 Objective-C

1. OC 的起源

OC 的方法(本质上讲是消息)在运行时决定。使用函数调用的语言,由编译器决定。如果涉及多态,则用到虚函数表。

2. 少在头文件中引用其他文件

  1. 两个头文件互相引用会导致编译错误
  2. 引用协议,超类时,无法使用前向声明(@class),只能引用头文件
  3. 协议一般放在单独的文件中,委托协议除外

3. 多用字面量语法

  1. 向数组中插入 nil 时,如果使用字面量会直接报错,如果是使用初始化方法,则 nil 以后的对象被忽略
  2. 字典也是同理

4. 多用常量,少用 #define

  1. 不在头文件里面声明预处理命令,防止被别的文件引用,static const 也不能用
  2. .m 文件里面声明的变量,需要加上 static,不然会产生外部符号,重复的外部符号会导致编译错误
  3. static const 定义只在类内部可见的常量
  4. extern 定义全局常量,并使用类名作为前缀
  5. 头文件中使用 static const 会在每个编译单元中出现一个字符串对象,而用 extern 定义的对象放在全局符号表中。参考链接:static const Vs extern const
  6. 使用 FOUNDATION_EXPORTextern 更好,参考链接:“FOUNDATION_EXPORT” vs “extern”

5. 用枚举表示状态和选项

  1. 按位或操作来组合的枚举使用 NS_OPTIONS 宏定义,不需要相互组合的用 NS_ENUM 来定义。
  2. 尽可能指定枚举变量的类型

对象、消息、运行期

6. 理解“属性”这一概念

  1. 如果直接使用实例变量,系统会根据偏移量来确定它们的位置。如果后来新增了实例变量,会导致重新编译。
  2. @property 的作用是合成存取方法
  3. @synthesize 的作用是指定实例变量的名字,目前默认会执行 @synthesize xxx = _xxx;
  4. @dynamic 的作用是不要创建实例变量,也不要创建存取方法

7. 在对象内部尽量直接访问实例变量

  1. 直接访问实例变量不会经过方法派发,不会触发内存管理语义,不会触发 KVO,无法调试(加断点)。
  2. 可以考虑通过直接读取实例变量来加快读取速度
  3. 初始化方法中不要调用 setter,这是因为子类有可能重写设置方法。参见 Demo 的 EOCSmithPerson.m 文件。
  4. 如果属性是惰性初始化的,必须通过 getter 来读取。

8. 理解对象等同性

  1. 应该保证相等的对象具有相等的 hash 值,但即使 hash 值不同,也不影响判断对象等同性。但是考虑到对象加入集合中的情况,我们总是应该为相同的对象提供相同的哈希值。
  2. 要么确保对象的哈希值不依赖内部可变的状态,要么确保依赖的状态不会改变。

9. 以“类族模式”隐藏实现细节

  1. 用类族模式可以将实现细节隐藏,返回基类的对象,并且通过多态完成任务。这其实是一种工厂模式。
  2. 注意此时调用 isMemberOf: superClass 的返回结果是 NO,因为对象实际上是子类的实例。调用 isKindOf: superClass 的返回结果则是 YES
  3. [arrayInstance class] = [NSArray class] 的返回结果总是 NO,因为左边一定是 NSArray 的子类。

10. 使用关联对象

  1. 使用静态全局变量作为键,设置好合适的内存管理语义

11. objc_msgSend

  1. 大部分消息调用使用了 objc_msgSend 函数。对于某些边界情况,运行时环境可能使用一些其他的函数来处理:objc_msgSend_stret:如果返回的是结构体,调用这个函数。objc_msgSend_fpret:如果返回的是浮点数,调用这个函数。objc_msgSendSuper:如果给超类发消息,调用这个函数。

12. 消息转发

  1. 分为三个步骤,动态方法解析,快速转发和完整转发
  2. 实现一个“字典”对象:TBD

14. 理解“类对象”

  1. 运行期检视对象类型被称为“内省”
  2. 因为类对象是单例,所以可以直接通过 == 判断类对象是否相等。但应该避免这么做,推荐使用类型信息查询方法(isMemberOfisKindOf)。TBD:举例说明

接口与 API 设计

15. 用前缀避免命名空间冲突

  1. 前缀至少是三个字母,两个字母的前缀由 Apple 保留
  2. 全局函数和变量需要注意避免冲突
  3. 在自己开发的库中,为用到的第三方库添加前缀

16. 全能初始化方法

  1. 设置一个全能初始化方法,别的初始化方法都调用它

17. 实现 description 方法

  1. 实现 description 方法,改变 NSLog 时的输出结果
  2. 实现 debugDescription 方法,改变 po 时的输出结果

18. 尽量使用不可变对象

  1. 不要把可变的 collection 作为属性公开,应该公开一个不可变的 collection 然后提供相关的修改方法

19. 命名方式

  1. 如果返回值是新建的,首个词是返回值类型
  2. 不要使用 str 这种简称,使用 string
  3. get 前缀仅在由“输出参数”保存返回值的方法中使用

21. 错误类型

  1. 严重的错误可以直接抛出异常(比如禁止调用父类的方法,需要子类重写)
  2. 一般的错误使用 NSError,指定 domain(全局常量)、错误码(枚举类型)和用户细信息。

22. NSCopying 协议

  1. 实现 NSCopying 协议,重写 copyWithZone 方法。
  2. 容器的拷贝总是浅拷贝,copymutableCopy 的区别只是返回对象是否可变。

协议与分类

23. 使用委托

  1. 调用 delegate 中的方法时,总是应该传入发起委托的对象。这样代理对象可以判断不同的委托者。

24. 使用分类

  1. 可以把所有的私有方法都归入名叫 Private 的分类中

25. 为第三方分类添加前缀

  1. 分类中定义的方法可以多次互相覆盖,以最后一个分类为准
  2. 向第三方类中添加分类时,为分类名称和方法名称添加前缀

26. 分类中不要声明属性

  1. 分类中无法创建实例变量
  2. 可以定义存取方法,但是不要定义属性

你可能感兴趣的:(OC读书笔记)