在读《OC2.0编写高质量iOS代码的52个方法》记录

一 熟悉OC 对象 消息 运行时

1.OC消息结构语言,其运行时所应执行的代码由运行环境决定; 动态性语言。 OC语言的对象所占的内存老是分配在堆空间,毫不会分配在栈空间。 指针的大小:32位4字节,64位机8字节。数组

2.在类的头文件里尽可能少引用其余头文件。 可使用@class向前声明类的方法。 这能够相应的减小编译时间。 注意:类遵循某个协议,就必须引用完整,不能使用向前声明方法。 (所以也就出现了:1.要么将协议移到class-continuation里;2.若是不行,就把协议单独放到一个头文件里,而后引入。)缓存

3.多使用字面量语法,少使用与之等价的方法 NSArray *array = [@"name", @"title"]; 而不要使用 NSArray *array = [NSArray arrayWithObjects:@"name",@"title",nil]; NSDictionary 同理。 这样子建立,就能够经过去下标的方式取对应的元素了。方便。安全

4.多用类型常量,少用#define 宏预处理 能够参考官方通知名称的写法。网络

5.用枚举表示状态、选项、状态码 首先枚举名字直接易懂。 枚举分 NS_ENUM 和 NS_OPTIONS。 具体使用:须要以按位或操做组合的都用NS_OPTIONS,不用互相组合的用NS_ENUM。 另外枚举使用switch的时候,不要加default。 这样子,新增枚举值,编译器就会给出警告信息。框架

6.属性 @property 自动生成set get方法。 ABI: Application Binary Interface 应用程序二进制接口。 assign: 只会执行“纯量类型(CGFloat, NSInteger)”的简单赋值操做。 strong: 定义一种拥有关系。 先保留新值,并释放旧值,而后再将新值设置上去。 copy:设置方法并不保留新值,而是将其拷贝。 weak:定义了一种“非拥有关系”。 设置方法既不保留新值,也不释放旧值。 对象摧毁时,属性也会清空nil。 unsafe_unretained: 和assign 相同,它适用于对象类型。 也是“非拥有关系”。 可是对象摧毁,不会置空nil。 这和weak的区别。函数

atomic:使用同步锁开销较大,会带来严重的性能问题。性能

7.在对象内部尽可能直接访问实例变量 读取实例变量的时候才用直接访问的形式,而在设置实例变量的时候经过属性来作。 懒加载必须经过“获取方法”来访问属性。atom

8.对象等同性 ==操做符比较的两个对象的指针自己,不是其所指的对象。 isEqual:方法判断两个对象的等同性。 若是isEqual判断两个对象相等,那么其hash方法也必返回同一个值。反之,不必定。spa

9.以类族的方式隐藏实现细节 参考UIButton的定义方法。 只需传入Button类型,不用管内部具体实现。系统框架方法里很是常见。线程

10.既有类中使用关联对象存放自定义数据 objc_setAssociatedObject()方法。 只有其余方法不行时才使用,由于这个方法一般会引入难于查找的bug。

11.理解objc_msgSend方法 在底层,全部的方法都是普通的C语言函数,然而对象收到消息以后,究竟该调用哪一个方法则彻底在运行期决定,甚至能够在程序运行时改变,这就是OC是一门真正的动态性语言。

12.理解消息转发机制 第一阶段:动态方法解析 +(BOOL) resloveInstanceMethod:(SEL)selector 在此方法里,你能够插入一个已经实现的方法。 第二阶段:完整的消息转发机制。网上有一个经典的处理流程图。 越日后处理的代价越大。

13.方法调配技术调试黑盒方法 method swizzling 方法交换。 这种方法不要乱用,不然出bug很难定位。

14.理解类对象的用意 类对象底层是Struct。 这个要掌握看看。 isa、 super_class、 *name、 version、info、instance_size.等等 isMemberOfClass:判断对象是否为某个特定类的实例。 isKindOfClass:对象是否为某个类或其派生类的实例。

第三大部分 API

15.加前缀避免命名空间冲突 注意:两字母大写前缀Apple爸爸宣称它保留使用的权利,因此咱们最好使用三字母前缀。

16.提供全能初始化方法 全部对象均要初始化。 若是有多种初始化方法,搞一个全能初始化方法,全部初始化方法都调用它。

17.实现description方法 实现description方法,返回一个更有意义的字符串,用于描述该实例。 若想在调试的时候打印更详尽的对象信息,应该实现debugDescription方法。

18.尽可能使用不可变对象 readonly 若是这个属性不想外部改变,就用readonly修饰。 若是外部只想调用某个属性, 能够在.h文件中修饰readonly,在.m文件里修饰为readwrite。

19.使用清晰而协调的命名方式 方法与变量使用驼峰式大小写命名方式。 方法命名不要吝啬使用长的方法名,定义的方法应该直接就能够看出其语义做用。

20.为私有方法加前缀 这样能够很好的共有方法区别开来。 不过注意:一个下划线方式(_)不要使用,Apple爸爸说这个要给它预留的。

21.Objective-C的错误类型 OC里的异常,只应该用于及其严重的错误(fatal error),不能够用其处理通常错误类型。 在错误不那么严重的状况下,可使用代理方式来处理、传递错误。 当NSError当参数传递错误时,实际上传递的是一个指针。 (NSError )error。 指针自己又指向一个指针,那个指针指向NSError对象。 在ARC下NSError 转化为 NSError*__autoreleasing* 的。 即:指针所指的对象会在方法执行完毕后自动释放。 这个队形也必须自动释放,由于处理错误的方法对象不能保证能够把方法中建立的NSError释放掉,因此必须autorelease。

22.NSCopying 协议 若是想让某个类支持copy操做,那就要实现NSCopying协议,该协议只有一个方法:

  • (id)copyWithZone:(NSZone *)zone; 注意是zone 不是 copy方法。 可变对象实现mutableCopyWithZone方法。 NSMutableCopying协议。 注意:可变对象使用copy,返回一个不可变的实例。 深拷贝:在拷贝对象自身时,将其底层数据也一并复制过去。 Foundation框架里全部的collection类,在默认状况下都是浅拷贝。只拷贝对象自己,而不复制器内容。

四 协议和分类

23.经过委托与数据源协议进行对象间的通讯Delegate 委托模式为对象提供了一套接口。

24.将类的实现代码分散到便于管理的数个分类之中category 利用分类机制把类的实现划分为易于管理的小模块。 私用方法纳入private分类中

25.老是要为第三方分类添加名称前缀 不加前缀容易覆盖原来的方法,一旦覆盖,以最后加载的一个分类为准。

26.不要在分类中声明属性 虽说能够经过objc_setAssociatedObject: 方法添加,可是不推荐。分类目标在于扩展类的功能,而非封装数据。 把封装数据所用的所有属性都定义在主接口里。

27.使用class-continuation分类 隐藏实现细节 将就在本类使用的属性写在class-continuation分类。若是只需外部访问的属性,能够在.h里声明成readonly。 .m文件里的@interface class {} @end

28.经过协议提供匿名对象 Id. ID类型, 至关于匿名。。

五 内存管理

29.理解引用计数 保留计数不能说必定是某个值,应该说你执行的操做,是递增了仍是递减了该计数。 XXX = nil; 悬挂指针,防止出现指向无效对象的指针,从而形成可能的crash。 autorelease:释放操做在下一次事件循环时才回收。 所以它能够延长对象的生命周期,使其跨越方法边界依然能够存活一段时间。 ARC下:不能够调用:retain release autorelease dealloc 方法

30.以ARC简化引用计数 内存泄漏:没有正确释放已经再也不使用的内存。 非OC对象,好比CoreFoundation中的对象,或是有malloc()分配在堆中的内存,要手动清理。 CFRelease。

31.在dealloc方法中只释放引用并解除监听 通知一旦发给了已经回收了的对象,必然crash。 dealloc方法里面不该该调用任何其余方法,由于此时对象已经接近尾声了。

32.编写“处理异常代码”时要注意内存管理问题 在OC 中应该程序必须因异常情况而终止时才应该抛出异常。fatal error(参见第21条)。 程序即将终止,内存能够不处理。 可是若是本身非要处理异常,必定要注意try 方法内清理好对象内存。 -fobjc-arc-exceptions 在ARC下大能够捕获异常标志。 可是这样运行效率会变低。

33.用弱引用避免保留环 weak 与 unsafe_unretained 做用彻底一致,然而weak修饰的属性,只要系统回收了,会自动设为nil。

34.用autoreleasepool 下降内存峰值 GCD、数组block遍历等线程都默认建立了自动释放池。每次执行“事件循环”时,就会将其清空。 autoreleasepool 能够多层嵌套, 它的做用范围就在其大括号{}之间。。 若是内存峰值不是很大,尽可能不要额外创建自动释放池。

35.用“僵尸对象”调试内存管理问题 Zoombie Objects 向已经回收的对象发送消息是不安全的。 不是必crash的。 这取决于:对象所占的内存有没有被其它内容所复写。。 系统会修改对象的ISA指针,令其指向特殊的僵尸类,从而使其变成僵尸对象。NSZombie 也是一个根类,和NSObject同样。 僵尸类能够响应任何选择子,响应方式:打印一套消息内容及接收者信息,并终止程序。

36.不要使用retainCount 由于retainCount返回的是某个节点的计数值,并不能考虑到后续系统可能会清掉、释放操做。 因此它是不能准确反映计数值得。

六 块与大中枢派发

37.理解块这一律念 Block:带有自动变量(局部变量)的匿名函数。 查看Block源码,它也有一个isa指针,因此实质上block就是OC对象。 Block根据存储区域分为三种: _NSConcreteStackBlock _NSConcreteMallocBlock _NSConcreteGlobalBlock 栈、堆、程序数据(静态)Block

38.一般用typedef建立块 方便写,也方便阅读。 block表达式: ^返回值类型 参数列表 表达式

39.使用handler块下降代码分散程度 通常获取网络数据用块处理很方便,由于在块定义范围内能够直接获取块内的全部变量。

40.使用块引用其所属对象时不要出现保留环 41.多用派发队列,少用同步锁 @synchronized(self){ //会下降代码效率,公用不用一个锁的同步块,都必须按顺序执行 } 使用同步队列及栅栏块,能够令同步行为更加高效。

42.多用GCD,少用performSelector系列方法 performSelector系列方法在内存管理方面容易有疏失。它没法肯定将要执行的选择子具体是什么,由于ARC编译器也没法适当的插入内存管理方法。

43.掌握GCD及操做队列的使用时机 在执行后台任务时,GCD并不必定是最佳方式。 还有一个NSOperationQueue。 SD库就是用的这方式。 它的好处: 能够取消某个操做, 可是已经启动的不能取消。 能够指定操做间的依赖关系。能够指定优先级。能够经过兼职观测机制监控NSOperation对象属性。

44.dispatch_group 注意一对函数。 dispatch_group_enter dispatch_group_leave 必然成对出现。 这个主要用于函数回调完了 在执行notify方法。

45.使用dispatch_once来执行只需运行一次的线程安全代码 dispatch_once简化代码并能完全保证线程安全。 更高效

46.不要使用dispatch_get_current_queue 此函数已经废除,最多在调试的时候使用

七 系统框架

47.熟悉系统框架 框架:将一系列代码封装成动态库,并在其中放入描述其接口的头文件, 这样作出来的东西就是框架。 48.多用枚举块,少用for循环 for in 和 block遍历方式。 block遍历方式能够根据options 反向遍历。 49.对自定义其内存管理语义的collection使用无缝桥接 __bridge 50.构建缓存是使用NSCache而非NSdictionary。 NSCache会在当系统资源耗尽时,它能够自动删除缓存。 先删除最久没使用的对象。 而且它也是线程安全的。 51.精简initialize和load的实现代码 若是分类和类都定义了load方法,先调用类的,在调用分类的。 整个应用程序在执行load时都会阻塞,因此load方法要精简。 initialize 方法是懒加载的。只有当程序用到了相关的类,才会调用。且只调用一次。 它也只应该设置类内部数据,不该该调用其它方法。 52.NSTimer会保留其目标对象 若是你的应用在iOS10以后,直接使用block方式建立就能够避免对象不释放这个问题。 也可使用NSWeakTimer三方库解决。

相关文章
相关标签/搜索