Effective-oc 笔记(上)
前五章内容:
熟悉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来替代:
- 可以加static 控制作用域、避免冲突
- 类型含义明确,维护性好
- static 编译器会自行优化为define
5.枚举
- 占用1字节
- type NS_ENUM oc枚举
- 根据编译平台决定使用新、旧协议(c++)
- 新协议指的是底层数据类型存储
- switch 处理enum分支;尽量不用default,覆盖每一个分支,避免新增enum,switch未处理的情况
6.属性
- 类对象保管存储偏移量
- @dynamic 配合CoreData动态添加方法
7.对象内部使用实例变量
self.var 语法
- 效率低
- 可触发kvo,可使用懒加载
_var
语法- 不触发kvo
- getter语法里使用
折中方案
- 写入用setter
- 读取用_var
8.对象等同性
- isEqualToString比isEqual快
- == 判断指针操作
- hash()方法用于比较,自己实现;注意set时 的hash 碰撞问题
- 结构对象使用主键比较
9.类簇
- oc没有概念上的抽象类,oc的抽象类不写init
- 类簇类似抽象类的概念,提供接口,不提供实现
- NSArray 里面是工厂,NSArray class 隐藏 无法通过实例访问
1
2
3
4
5
6
7
8NSArray *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
- 配合@dynamic
- 备用接受者 forwardingTargetForSelector
- 返回接收对象
- 1对1
- 快速
- 完成消息转发forwardInvocation
- 修改方法内容
- 1对多
- 慢
13.方法交换
- 用于调试目的
- 用户行为监控
- 调试异常
- 一般应用层不建议使用
14.类对象意义
- 判断对象关系 isKindOf isMemberOf;
- 示例:NSProxy 对于isKinfOf 对 class处理可能不一样(消息转发)
- 消息传递机制的前提
15.用前缀避免命名空间冲突
- c函数需要加前缀
- lib对象,自己引用的第三方加前缀
16.全能初始化器
和swift的指定初始化器类似,swift 强制性 oc 没有这种约束 designted翻译差异。
中文翻译的怪怪的;
我的翻译是:
目标是为了实例的初始化能保证类和其父类的所有成员得到初始化- 全能初始化器的作用是为了保证当前类成员得到初始化
- 非全能初始化器应调用当前类全能初始化器
- 子类的全能初始化器必须调用父类的全能初始化器
- 如果父类的全能初始化器,子类没有实现,那么实例可以直接调用父类的全能初始化器初始化,子类成员变量没有初始化。为了解决这个问题,要么 抛异常,要么 重写父类的全能初始化器
这块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