

第五章 内存管理
第29条、理解引用计数
29.一、引用计数的工做原理
在引用计数框架下,对象有个计数器,用以表示当前有多少个事物想令此对象继续存活下去。这在OC中叫作 “保留记数”,也叫 “引用计数”。编程
引用计数机制经过能够递增递减的计数器来管理内存。对象建立好以后,其保留计数至少为1。若保留计数为正,则对象继续存活。当保留计数降为0时,对象就被销毁了。数组
NSObject 协议声明了下面三个方法用于操做计数器:缓存
- retain 递增保留计数
- release 递减保留计数
- autorelease 自动释放
为避免在不经意间使用了无效对象,通常调用完 release 以后都会清空指针。这样能保证不会出现可能指向无效对象的指针,这种指针一般被称为 “悬挂指针”。安全
29.二、属性存取方法中的内存管理
- (void)setFoo:(id)foo {
[foo retain];
[_foo release];
_foo = foo;
}复制代码
29.三、自动释放池
在 OC 的引用计数架构中。调用 release 会马上递减对象的保留计数,这里可该用 autorelease,此方法会在稍后递减计数,一般在洗下一次 “事件循环” 时递减,不过也可能提早执行。网络
autorelease 能延长对象生命期,使其在跨越方法调用边界后依然能够存活一段时间。数据结构
第30条、以 ARC 简化引用计数
能够经过编译器的 “静态分析器” 来指明程序里引用计数出问题的地方。能够根据须要,预先加入适当的保留或释放操做以免内存管理的问题。
闭包
因为 ARC 会自动执行 retain、release、autorelease等操做,因此直接在ARC下调用这些内存管理方式是非法的。架构
ARC 在调用这些方法时,并不经过消息派发机制,而是直接调用其底层C语言版本,这样作性能更好,由于保留及释放操做须要频繁操做,因此直接调用底层函数能节省不少CPU周期。好比:ARC会调用与 retain 等价的底层函数 objc_retain。框架
30.一、使用ARC时必须遵循的方法命名规则
将内存管理语义在方法名中表示出来早已成为OC的惯例,而 ARC 则将之确立为硬性规定。这些规则简单滴体如今方法名上。若方法名如下列词语开头,则其返回的对象归调用者全部:异步
- alloc
- new
- copy
- mutableCopy
ARC 经过命命约定将内存管理规则标准化,除了会自动调用 “保留” 与 “释放” 方法外,使用ARC 还有其余好处,他能够执行一些手工操做很难甚至没法完成的优化。
如:ARC 会把可以互相抵消的 retain、release、autorelease 操做约简。若是发如今同一个对象上执行了屡次 “保留” 与 “释放” 操做,那么 ARC 有时能够成对地移除这两个操做。
30.二、变量的内存管理语义
注意与属性的内存管理语义区分
可用下列修饰符来改变局部变量与实例变量的语义:
- __strong:默认语义,保留此值;
- __unsafe_unretained:不保留此值,这么作可能不安全,由于等到再次使用变量时,其对象可能已经回收了;
- __weak:不保留此值,可是变量能够安全使用,由于若是系统把这个对象回收了,那么变量也会自动清空;
- __autoreleasing:把对象 “按引用传递” 给方法时,使用这个特殊的修饰符。此值在方法返回时自动释放。
第31条、在 dealloc 方法中只释放引用并解除监听
- 在 dealloc 方法里,应该作的事情就是释放指向其余对象的引用,并取消原来订阅的 KVO 或 NSNotifaicationCenter等通知,不要作其余事情;
- 若是对象持有文件描述等系统资源,那么应该专门编写一个方法来释放此种资源。这样的类要和其使用者约定:用完资源后必须调用 close 方法;
- 执行异步任务的方法不该在 dealloc 里调用,只能在正常状态下执行的那些方法也不该在 dealloc 里调用,由于此时对象已经处于正在回收的状态了;
- 在 dealloc 里也不要调用属性的存取方法。
第32条、编写 “异常安全代码” 时留意内存管理问题
- 捕获异常时,必定要注意将 try 块内所创立的对象清理干净;
- 在默认状况下,ARC 不生成安全处理异常所需的清理代码。开启编译器标志后,可生成这种代码,不过会致使应用程序变大,并且会下降运行效率。
第33条、以弱引用避免保留环
- 将某些引用设为 weak,可避免出现 “保留环”;
- weak 引用能够自动清空,也能够不自动清空。自动清空是随着 ARC 而引入的新特性,由运行期系统来实现。在具有自动清空功能的弱引用上,能够随意读取其数据,由于这种引用不会指向已经回收过的对象。
第34条、以 “自动释放池块” 下降内存峰值
- 自动释放池排布在栈中,对象收到 autorelease 消息后,系统将其放入最顶端的池里;
- 合理运用自动释放池,可下降应用程序的内存峰值;
- @autoreleasepool 这种新式写法能建立出更为轻便的自动释放池。
第35条、用 “僵尸对象” 调试内存管理问题
第36条、不要使用 retainCount
NSObject 协议中定义 - (NSUInteger)retainCount
用于查询对象当前的保留计数。然而 ARC 已经将此方法废弃了。
此方法之因此无用,其首要缘由在于:任何给定时间点上的 “绝对保留计数” 都没法反映对象生命期的全貌。
第6章 Block 与 GCD
第37条、理解 “块” 这一律念
- 块是C、C++、Objective-C 中的词法闭包;
- 块可接受参数,也可返回值;
- 块能够分配在栈或堆上,也能够是全局的。
第38条、为经常使用的块类型建立 typedef
- 以 typedef 从新定义块类型,可令块变量用起来更加简单;
- 定义新类型时应听从现有的命名习惯,勿使其名称与别的类型相冲突;
- 不妨为同一个块签名定义多个类型别名。
第39条、用 handler 块下降代码分散程度
- 在建立对象时,可使用内联的 handler 块将相关业务逻辑一并声明;
- 在有多个实例须要监控时,若是采用委托模式,那么常常须要根据传入的对象来切换,而若该用 handler 块来实现,则可直接将块与相关对象放在一块儿;
- 设计 API 时若是用到了 handler 块,那么能够增长一个参数,使调用者可经过此参数来决定应该把块安排在哪一个队列上执行
第40条、用块引用其所属对象时不要出现保留环
- 若是块所捕获的对象直接或间接地保留了块自己,那么得小心保留环问题;
- 必定要找个适当的时机解除保留环,而不能把责任推给 API 的调用者。
第41条、多用派发队列,少用同步锁
- 派发队列可用来表述同步语义,这种作法要比使用 @synchronized 块或 NSLock 对此昂更简单;
- 将同步与异步派发结合起来,能够实现与普通加锁机制同样的同步行为,而这么作却不会阻塞执行异步派发的线程;
- 使用同步队列及栅栏块,能够令同步行为更加高效。
第42条、多用 GCD,少用 performSelector 系列方法
第43条、掌握 GCD 及操做队列的使用时机
第44条、经过 Dispatch Group 机制,根据系统资源情况来执行任务
第45条、使用 dispatch_once 来执行只需运行一次的线程安全代码
第46条、不要使用 dispatch_get_current_queue
第7章 系统框架
第47条、熟悉系统框架
将一系列代码封装为动态库,并在其中放入描述其接口的头文件,这样作出来的东西就叫框架。
Foundation 框架中的类,使用 NS 这个前缀,此前缀是在 OC语言 做为 NeXTSTEP 操做系统的编程语言时首度肯定的。
CoreFoundation,与 Foundation 框架相伴。Foundation 框架中的许多功能,均可以在此框架中找到对应的C语言 API。
AppKit 及 UIKit,构建在 Foundation 与 CoreFoundation 之上的 OC类。
- 许多系统框架均可以直接使用。其中最重要的是 Foundation 与 CoreFoundation,这两个框架提供了构建应用程序所需的许多核心功能;
- 不少常见任务都能用框架来作,例如音频与视频处理、网络通讯、数据管理等;
- 用纯C写成的框架与用OC写成的同样重要,若想成为优秀的OC开发者,应该掌握C语言的核心概念
第48条、多用块枚举,少用for循环
- 遍历集合有四种方式。最基本的办法就是 for 循环、其次是 NSEnumerator 遍历法、快速遍历法和 “块枚举法”;
- “块枚举法” 自己就能经过 GCD 来并法执行遍历操做,无需另行编写代码。而采用其余遍历方法则没法轻易实现这一点;
- 若提早知道待遍历的 collection 含有何种对象,则应修改块签名,指出对象的具体类型。
第49条、对自定义其内存管理语义的 collection 使用无缝桥接
OC 的系统库包含至关多的 collection 类,其中有各类数组、各类字典、各类set。
Foundation 框架定义了这些 collection 及其余各类 collection 所对应的 OC 类。
CoreFoundation 框架也定义了一套 C语言API,用于操做表示这些 collection 及其余各类 collection 的数据结构。
例如:
NSArray 是 Foundation 框架中表示数组的 OC 类。
CFArray 是 CoreFoundation 框架中的等价物。
这两种建立数组的方式也许有区别,然而有项强大的功能可在这两个类型之间平滑转换,他就是 “无缝桥接”。
第50条、构建缓存时选用 NSCache 而非 NSDictionary
NSCache 是 Foundation 框架专门处理缓存任务而设计的
- 实现缓存时应选 NSCache 而非 NSDictionary 对象。由于 NSCache 能够提供优雅的自动删减功能,并且是 “线程安全的”,此外,它与字典不一样,并不会拷贝键;
第51条、精简 initialize 与 load 的实现代码
- 在加载阶段,若是类实现了 load 方法,那么系统就会调用它。分类里也能够定义此方法,类的 load 方法要比分类中的先调用。与其余方法不一样,load 方法不参与覆写机制;
- 首次使用某个类以前,系统会向其发送 initialize 消息。因为此方法听从普通的覆写规则,因此一般应该在里面判断当前要初始化的是哪一个类;
- load 与 initialize 方法都应该实现得精简一些,这有助于保持应用程序的响应能力,也能减小引入 “依赖环” 的概率;
- 没法在编译器设定的全局常量,能够放在 initialze 方法里初始化。
第52条、别忘了 NStimer 会保留其目标对象
- NSTimer 对象会保留其目标,直到计时器自己失效ei zhi