《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(下)

Posted WoodBear009

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(下)相关的知识,希望对你有一定的参考价值。

1.为避免在不经意间使用了无效对象,一般在release之后会清空指针,=nil;

2.通常利用弱引用或者“手动”解除引用的方式破坏循环引用。

3.ARC下,规定以alloc、new、copy、mutabelCopy开头方法,调用者要负责返回对象的释放;反之,返回的对象会自动释放,调用者要注意对返回值的保留。

4.属性设置的正确流程:保留新值,释放旧值,更新变量。

5.ARC下dealloc的使用:

(1)不必调用[super dealloc] 

(2)在dealloc中可以做KVO\\NSNotification的移除清理工作

(3)在dealloc中要释放一些非OC对象,比如C API生成的对象

(4)一些开销较大或者稀缺的资源尽量用完后或者再合适的时机及时释放,不要等到dealloc中再做释放、清理处理

(5)不要在dealloc中做一些异步处理,也不要调用在正常情况下执行的代码(就是要注意对象此时处在的是回收状态,不安全)

6.异常的产生会缩短代码的执行周期(跳过代码的执行,对象(资源)释放的代码被跳过),在MRC下,可以在final中做对象(资源)的释放;而在ARC下默认不会处理异常情况下的对象(资源)释放,需要手动设置-fobjc-arc-exceptions。因为系统建议只有在发生极其严重的问题时才抛出异常,这类问题应导致应用的直接终止,所以默认情况下不必再去考虑异常情况下的内存管理问题。如果代码中发生了异常,应首先考虑的是解决异常问题,而不是捕获异常,发生其他错误可考虑使用NSError等方式处理。

7.利用自动释放池降低内存峰值

8.将NSZombieEnabled设置为YES,可以帮助调试“野”指针问题。原理:系统回收对象时,不真的把它回收,而是修改对象的isa指针,令其指向僵尸类,使其成为僵尸对象。当访问僵尸对象后,会打印一条包含消息内容和接收者的消息,然后终止应用,方便调试。

9.不要用retainCount,不可靠

10.块本身可视为对象,有引用计数。如果块捕获的是对象类型,会自动保留它,系统在释放块的时候,也会将其一并释放,以便平衡捕获时做的保留操作。

11.块本身也是对象。结构中第一个变量是一个Class对象指针(isa).invoke变量是个函数指针,指向块的实现代码,块其实就是一个代替函数指针的结构。descriptor指向一个结构体,其中声明了块的大小,还包含copy和dispose两个辅助函数对应的函数指针。辅助函数在拷贝和丢弃块对象时,会执行一些操作。前者保留捕获的对象,后者负责将其释放。块还会把它捕获的所有变量都拷贝一份(不是拷贝对象本身,只是指向这些对象的指针变量),这些拷贝都放到了descriptor后面,捕获了多少,就占多少内存。

12.block大部分情况下默认分配在栈区(_NSConcreteStackBlock)中。可以手动通过copy将block从栈复制到堆区(_NSConcreteMallocBlock),复制后,block就成了带有引用计数的对象,后续再做copy操作,只是增加引用计数。除了_NSConcreteStackBlock、_NSConcreteMallocBlock还有_NSConcreteGlobalBlock,如果block是个全局变量或静态变量或静态全局变量,或者block没有使用(截获)任何的局部变量,则block默认被分配到了全局区(数据段)。

13.使用typedef简化block的使用,typedef int(^TestBlock)(int a);

14.block相较delegate,可以使逻辑更为紧凑。

15.一定要在合适时机解除循环引用,而不要把责任推给外部API的调用者。******

16.可以利用串行队列解决同步问题.异步执行会有块拷贝的处理,如果块本身的拷贝代价大于块内任务本身的处理代价,则同步执行的效率反而会更高。

17.利用dispatch_barrier可以处理类似读写者的同步问题。

18.尽量使用GCD,少用performSelector方法。performSelector可能会引起内存方面问题,同时对方法的返回值及参数都有限制,不够灵活。

19.使用NSOperationQueue的好处:

     (1)OC API;

     (2)可取消尚未执行的任务;

     (3)可指定任务间的依赖;

     (4).可通过KVO观察NSOperation的一些属性(isCancelled/isFinished)等;

     (5).可指定任务的优先级.GCD的优先级是针对整个队列的;

     (6).可以实现NSOperation的子类。

20.遍历collection有4种方式。最基本的是for循环,其次是NSEnumerator及快速遍历,最新,最先进的是块枚举法。块枚举法即可获得对象,又可同时知道下标,还提供终止遍历的方式,同时还可以通过设置NSEnumerationConcurrent使其支持并发遍历操作。

21.Dict的快速遍历写法

for (NSString *key in dict)
        NSLog(@"%@",dict[key]);
    
22.实现缓存时可考虑使用NSCache。相较NSDictionary,NSCache线程安全,且支持LRU自动删减,同时不会拷贝键。可以给NSCache设置缓存对象个数与缓存总成本,但仅对NSCache起指导意义。

23.当类或分类被载入时会调用load方法.一个类的load方法不用写明[super load],父类就会收到调用,并且在子类之前。Category的load也会收到调用,但顺序上在主类的load调用之后。顺序即为:父类->本类->类别。每个类的load方法执行顺序无法保证,在load类中使用其他类(其他类可能会依赖其自身的load)是不安全的.load方法中任务尽量要精简,因为load执行时程序会被阻塞,程序必须等待所有类的load方法都执行后,才能继续。

     initialize的自然调用是在第一次主动使用当前类的时候.和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍。注意的是,在此之前,父类的方法已经被执行过一次了,同样不需要super调用(如果父类实现了,子类即便不实现,在第一次使用时,父类的initialize会被执行两次)。initialize应该只用来设置内部数据,尽量不要使用外部类或自身别的内部方法(有可能外部类(内部方法)本身又依赖了本类,而本类尚未初始化完成).

24.注意NSTimer引发的引用问题。一次性Timer会自动失效,而重复性timer需要手动invalidate.

以上是关于《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(下)的主要内容,如果未能解决你的问题,请参考以下文章

Effective Objective-C 2.0 — 第14条:理解“类对象“的用意

《Effective Objective-C 2.0》读后总结 之五

《Effective Objective-C 2.0》读后总结 之四

《Effective Objective-C 2.0》读后总结 之三

《Effective Objective-C 2.0 》 阅读笔记 item8

EFFECTIVE OBJECTIVE-C 2.0 TIPS 总结 CHAPTER 1 & CHAPTER 2