前五章内容:
熟悉oc 1-5
对象、消息、runtime 6-14
接口与API 15-22
协议与分类 23-28
内存管理 29-36

1.oc起源

2.减少头文件引用

  • 如果不使用类方法可以仅声明@class Class 即可

3.多用字面量

  • 代码整洁、直观
  • NSArray arrayWithObject:遇到nil不会崩溃,内部会判断

4.少用define

  • 建议使用const来替代:
    1. 可以加static 控制作用域、避免冲突
    2. 类型含义明确,维护性好
    3. static 编译器会自行优化为define

5.枚举

  • 占用1字节
  • type NS_ENUM oc枚举
    1. 根据编译平台决定使用新、旧协议(c++)
    2. 新协议指的是底层数据类型存储
    3. switch 处理enum分支;尽量不用default,覆盖每一个分支,避免新增enum,switch未处理的情况

6.属性

  • 类对象保管存储偏移量
  • @dynamic 配合CoreData动态添加方法

7.对象内部使用实例变量

  • self.var 语法

    1. 效率低
    2. 可触发kvo,可使用懒加载
  • _var 语法

    1. 不触发kvo
    2. getter语法里使用
  • 折中方案

    1. 写入用setter
    2. 读取用_var

8.对象等同性

  • isEqualToString比isEqual快
  • == 判断指针操作
  • hash()方法用于比较,自己实现;注意set时 的hash 碰撞问题
  • 结构对象使用主键比较

9.类簇

  • oc没有概念上的抽象类,oc的抽象类不写init
  • 类簇类似抽象类的概念,提供接口,不提供实现
  • NSArray 里面是工厂,NSArray class 隐藏 无法通过实例访问
    1
    2
    3
    4
    5
    6
    7
    8
    NSArray *arr = [[NSArray alloc] init];
    NSLog(@"%@|%@",[arr class], [NSArray class]);
    NSString *str = [[NSString alloc] init];
    NSLog(@"%@|%@",[str class], [NSString class]);

    ///分别打印
    __NSArray0|NSArray
    __NSCFConstantString|NSString

10.动态添加属性

  • 本质是全局创建Map,以Class为key的外部表
  • 示例:UIAlertView存在多个,通过此方法区分每个;不建议这么用;不好定位异常

11.消息派发

  • objc_msg_send 有两个隐藏参数 (id,SEL)
  • runtime
  • 尾调用优化:去掉函数栈帧,优化

12.消息转发

  • resolveInstanceMethod/resolveClassMethod
    1. 配合@dynamic
  • 备用接受者 forwardingTargetForSelector
    1. 返回接收对象
    2. 1对1
    3. 快速
  • 完成消息转发forwardInvocation
    1. 修改方法内容
    2. 1对多

13.方法交换

  • 用于调试目的
    1. 用户行为监控
    2. 调试异常
    3. 一般应用层不建议使用

14.类对象意义

  • 判断对象关系 isKindOf isMemberOf;
  • 示例:NSProxy 对于isKinfOf 对 class处理可能不一样(消息转发)
  • 消息传递机制的前提

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

  • c函数需要加前缀
  • lib对象,自己引用的第三方加前缀

16.全能初始化器

  • 和swift的指定初始化器类似,swift 强制性 oc 没有这种约束 designted翻译差异。

  • 中文翻译的怪怪的;
    我的翻译是:
    目标是为了实例的初始化能保证类和其父类的所有成员得到初始化

    1. 全能初始化器的作用是为了保证当前类成员得到初始化
    2. 非全能初始化器应调用当前类全能初始化器
    3. 子类的全能初始化器必须调用父类的全能初始化器
    4. 如果父类的全能初始化器,子类没有实现,那么实例可以直接调用父类的全能初始化器初始化,子类成员变量没有初始化。为了解决这个问题,要么 抛异常,要么 重写父类的全能初始化器

    这块swift做成了编译检查,而且swift官方文档描述的更清楚

17.实现descripion方法

  • 自己实现的建议加上类名称和对象地址
  • lldb里po 打印的是debugDescripion

18.使用不可变对象

  • 涉及到扩展的作用外部ro,内部rw可以点语法修改
  • 成员变量对外不可变,修改交给类内部

19.命名方式

20.为私有方法加前缀

  • oc由于动态机制,没有所谓的private函数
  • 不要用_作为前缀,和苹果自带的冲突

21.oc错误类型

  • 使用抽象类建议抛出异常
  • NSError** 使用

22.NSCopying协议

  • copy方法调用copyWithZone;注意重写的应是copyWithZone

23.delegate对象间通信

  • delegate属性weak
  • 自定义代理调用需要判断是否实现方法
  • 位域代替responseToselector

24.类拆分成多个分类

  • 方便管理类
  • 函数调用栈里可以看到分类信息

25.分类方法加前缀

  • 分类加前缀
  • 分类方法加前缀

26.分类中不能添加属性

  • 可以通过同名函数做到模拟属性的效果 不推荐
  • 关联值添加属性 不推荐
    感觉翻译的还是有点问题
    原文:“你可能通过属性特质修改了某个属性的管理语义”
    理解:如果要给一个类批量修改属性@property,一般只记得在主类的头文件修改;如果设置了关联值,很可能忘记修改,维护性差

27.匿名分类隐藏实现细节

  • 和c++混编时,c++对象放到匿名分类里,避免重复引用头文件造成
  • 修改ro属性,内部为rw
  • 隐藏遵守的协议
  • 私有属性,没在.h里,一般看不到;私有变量和放在impl里作用相同

28.协议实现匿名函数

  • pop面向协议编程
  • 隐藏实现,仅暴露协议内容

29.理解引用计数

  • retainCount 不推荐;因为如果autorelease了retainCount值不准确
  • mrc return [对象 autorelease],避免调用者不释放

30.ARC简化引用计数

  • autorelease 后的返回函数 接收强类型对象 编译会自动retain
  • 不能复写release函数
  • CF对象自行释放

31.dealloc作用

  • 不要调用存取方法
  • 可能并不会触发、在应用异常退出;可以在ApplicationWillTerminate里释放
  • 某些文件句柄、socket系统映射文件,不要直接释放、调用相应close方法
  • 释放c对象
  • 释放通知、kvo

32.捕获异常

  • arc 下不建议 try catch ,加很多辅助代码
  • 如果objc++ 可以处理try catch

33.弱引用避免循环引用

  • weak属性 避免出现引用闭环

34.自动释放块

  • 可以在循环中创建对象使用,控制内存

35.僵尸对象调试

  • 打开编译开关
  • 原理:生成僵尸子类,由僵尸子类处理消息

36.retainCount

  • 不建议用
  • 由于autorelease,某一个时刻不代表真实值
  • 优化原因,可能永远不为0
  • 常量区对象也会有retainCount值,int.max