《Effective Objective-C 2.0》读书笔记

本篇博客作为读书笔记,主要记录和整理阅读EOC(《Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法》)时的收货和感悟

1.了解OC语言的起源

了解OC的语言特性(运行时),OC的发展来源(C的超集),语法,内存管理策略等。

2.在类的头文件中尽量少引入其他头文件

在.h中引入其他头文件,会大幅度增加编译所需的时间,也有可能会导致循环引入的问题。应当尽量使用“前向声明”(@class)的方式来声明其他类的存在。 为了避免在.h中引入定义协议的头文件,遵守协议应该写在.m中的类扩展里,而不是写在.h中

3.多用字面量语法,少用与之等价的方法

了解和掌握用于快速创建NSNumber、NSArray、NSDictionary的字面量语法:@num,@[],@{};以及相应的下标运算符。需要了解数组和字典创建时遇到nil值会结束的特性,以及使用字面量语法带来的好处。

4.多用类型常量,少用#define预处理指令

在定义仅类内部使用的常量时,应该尽量使用static const的方式来定义。这种定义的会限制其类型,并且避免其他文件的修改。当定义全局变量时,应使用在类内部定义全局变量,在头文件中使用extern引用全局常量的做法。

5.用枚举表示状态、选项、状态码

了解为什么用枚举更好、怎么使用C++11带来的新枚举用法,以及OC中定义的快速创建枚举宏的用法。了解和掌握NS_ENUM和NS_OPTIONS宏的用法。

6.理解“属性”这一概念

使用@property语法时,编译器会自动生成getter方法和setter方法以及成员变量的。掌握@property的关键字:四种类型(原子性、内存管理策略、读写性、读写方法重命名),以及分别的使用场景和原理。

7.在对象内部尽量直接访问实例变量

了解通过属性访问实例变量会触发什么(调用setter或getter方法,触发KVO)了解使用属性来访问成员变量和直接访问成员变量两者的区别与优劣:直接访问成员变量效率更快。

8.理解“对象等同性”这一概念

了解isEqual:这一方法的原理,了解NSString中isEqualToString:这一方法做了什么事情。了解如果需要自定义方法来判断两个对象是否相等应该怎么做。

9.以“类族模式”隐藏实现细节

了解类族的概念,了解如何通过工厂方法来创建类族子类对象。掌握如何通过工厂模式设计工厂方法来实例化子类对象。

10.在既有类中使用关联对象存放自定义数据

掌握runtime中的objc_setAssociatedObjectobjc_getAssociatedObject方法的作用和用法。掌握冬天获取和添加成员变量的方式。

11.理解objc_msgSend的作用

理解和掌握OC中的消息机制,理解”selector”、”IMP”的含义。了解objc_msgSend方法的意义

12.理解消息转发机制

了解OC运行时机制,了解当消息接收者无法处理消息时,会调用哪些方法。掌握使用resolveInstanceMethod:resolveClassMethod:方法来动态添加方法、使用forwardingTargetForSelector:方法来转发消息、使用forwardInvocation:方法来处理完整的消息转发。

13.用“方法调配技术”调试“黑盒方法”

了解和掌握runtime方法调用流程,了解”method swizzling”的原理和用法,掌握使用class_getInstanceMethodclass_getClassMethod函数来获取方法实现,使用method_exchangeImplementations函数来交换方法实现。同时需要了解在使用”method swizzling”时,自定义的方法中如何规避调用自身的问题。

14.理解“类对象”的用意

了解OC对象的实现方式,了解“类对象”,“isa指针”,“元类对象”的概念。掌握isMemberOfClass:方法和isKindOfClass:方法的作用。

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

理解编写自己的类时,使用命名前缀。

16.提供“全能初始化方法”

理解和掌握在类的初始化方法中提供一个被其他所有初始化方法调用的“全能初始化方法”。其他初始化方法都调用这个方法来创建实例对象,在这个初始化方法中进行对象的具体配置。

17.实现description方法

掌握通过重写自定义类的description方法来实现描述信息的返回。了解使用debugDescription方法在LLDB中进行调试打印。

18.尽量使用不可变对象

理解定义公开属性时尽量使用不可变版本的原因,了解在类扩展中修改为readwrite以便类内部可以修改。了解对外公开的集合属性的返回方式。

19.使用清晰而协调的命名方式

了解OC中方法名的命名规范,了解驼峰法书写方式,方法名在言简意赅的同时最好能完整叙述方法的功能,并给每个参数都加上相应的提示。 方法名中不要使用类型名的缩写而是使用类型名的全称。类名、协议名要加上对应的前缀。

20.为私有方法名加前缀

为了避免与公有方法混乱,或是无意中覆盖了父类中的共有方法,在书写类的私有方法时应该给方法加上前缀,比如以p_为前缀。不要仅使用一个单下划线_作为私有方法的前缀,避免和系统类的私有方法重合。

21.理解Objective-C错误模型

了解NSException的使用方法和应用场景。了解NSError的使用。

22.理解NSCopying协议

在OC中想要拷贝一个对象时,通常使用copy方法。该对象对应的类需要遵循NSCopying协议,并实现协议中的copyWithZone:方法。如果需要拷贝可变的版本,则需要遵守NSMutableCopying协议并实现mutableCopyWithZone:方法。了解深拷贝和浅拷贝的区别以及实现方式。

23.通过委托与数据源协议进行对象间通信

理解OC中代理设计模式的实现思路,掌握delegate和dataSource形式的协议设计。性能优化方面,可以将代理是否实现了代理方法在赋值时进行缓存,可以大大优化频繁调用代理方法时的效率。

24.将类的实现代码分散到便于管理的数个分类中

可以将不同模块的代码分散到类的分类中,仅把主要的核心代码保存在主文件中。分类既可以存放在主文件的中,划分不同模块保存,也可以创建不同的分类文件进行保存。

25.总是为第三方类的分类名称加前缀

为了避免重名的情况,分类文件名都应该尽量加上前缀。为了避免分类中的方法实现覆盖了其他分类中的实现或原实现,应该给方法名也加上相应的前缀。

26.勿在分类中声明属性

由于分类中不会合成属性对应的成员变量,因此不应该在分类中声明属性。虽然可以使用runtime动态添加的方式绑定,但这一并不好,不应该在非必须的时候这样做。分类中应该尽量只用来扩充方法。

27.使用“class-continuation分类”隐藏实现细节

掌握使用类扩展来给类扩充私有实例变量。如果想要使主接口中声明为“只读”的属性能够在内部修改,应该在类扩展中将其改写为“可读写”

28.通过协议提供匿名对象

了解通过协议来隐藏对象类型细节。如果具体类型不重要,重要的是对象能响应的方法,可以使用匿名对象的方式实现。

29.理解引用计数

了解和掌握OC中进行内存管理的机制,了解引用计数的概念,以及在MRC环境下进行对象内存管理所需使用到的常用方法(retain,release,autorelease,delloc)。

30.以ARC简化引用计数

了解ARC的概念,明白编译器在ARC环境下做了哪些事情。并且理解循环引用的概念,了解怎么在ARC模式下怎么避免内存泄漏。

31.在delloc方法中只释放引用并解除监听

在delloc方法中只应该进行释放对象引用(尤其是CF中的对象),以及移除观察者、通知监听的操作。如果有大量占用内存的对象需要提前释放,应该在自定义的方法中释放。

32.编写“异常安全代码”时留意内存管理问题

由于在ARC环境下,捕获异常时没办法释放对象引用,所以需要开启编译器的-fobjc-arc-exceptions标志来避免内存泄露。不过在非必要的时候不要开启,避免对性能的影响。

33.以弱引用避免保留环

当有循环引用时,使用weak指针(__weak修饰符)来修饰对象,避免循环引用导致的内存泄漏。

34.以“自动释放池块”降低内存峰值

在MRC环境下,可以通过手动创建自动释放池的方式来提前释放内存。

35.用“僵尸对象”调试内存管理问题

通过在编译器scheme中编辑中打开僵尸对象的监测来解决悬垂指针的问题。了解僵尸对象的概念和行成过程。

36.不要使用retainCount

即使在MRC模式下,retainCount方法返回的引用计数也并不可靠,不要使用该方法进行对象内存管理的判断。

37.理解“块”这一概念

了解block的基本概念和使用场景,了解自定义block类型的方式。了解block对象的内存管理情形。

38.为常用的块类型创建typedef

掌握使用typedef给block起别名,把类中常用的block类型定义为自定义的数据类型。

39.用handler块降低代码分散程度

掌握使用block回调的方式进行传值,使用completionHandler来处理完成回调,或者以两个block参数分别作为成功和失败的回调。这样做比使用delegate的方式更加便捷,并且具有可读性。

40.用块引用其所属对象时不要出现保留环

由于block会自动捕获其中使用到的对象,对其进行一次引用,所以在使用block时需要注意循环引用的情况。可以通过手动解除引用的方式解决,也可以通过将被捕获的对象用__weak修饰符修饰的方式解决。

41.多用派发队列,少用同步锁

当需要自己编写带有线程安全机制的代码时,可以考虑使用GCD的同步异步函数方式来实现。

42.多用GCD,少用performSelector系列方法

performSelector方法由于存在内存管理的缺陷,以及参数和返回值类型限制等问题,不建议使用。最好使用GCD的方法来实现方法调用和线程通信。

43.掌握GCD及操作队列的使用时机

了解和掌握NSOperation的使用,在实现多线程时也可以考虑使用。当需要处理任务取消、添加依赖、键值观察、指定任务优先级这些gcd无法实现的功能时应该用NSOperation来解决。

44.通过Dispatch Group机制,根据系统资源状况来执行任务

当需要等待某个或某些任务执行完毕时,可以通过将任务添加到一个队列组的方式实现。使用dispatch_group_notify方法来实现当队列中任务全部完成时执行某一代码块。

45.使用dispatch_once来执行只需运行一次的线程安全代码

当需要编写在整个程序运行的生命周期中只会运行一次的代码,可以使用gcd的dispatch_once函数来实现。单例设计模式中推荐使用这种方式而不是线程锁

46.不要使用dispatch_get_current_queue

dispatch_get_current_queue函数已经废弃,而且该函数返回的队列很可能与开发者预期的不同,因此使用的时候容易出现问题。应使用队列特定数据的方式来解决。

47.熟悉系统框架

熟练掌握Foundation框架和CoreFoundation框架的主要功能,熟悉常用的音频视频处理、网络通信、数据管理等系统框架,避免在开发中自己去实现一些系统已经实现好了的功能。

48.多用块枚举,少用for循环

掌握几种遍历集合的方式,掌握使用块循环enumerateObjectsUsingBlock:方法来实现遍历。

49.对自定义其内存管理语义的collection使用无缝桥接

了解和掌握Foundation对象和CoreFoundation数据结构之间转换的方式。

50.构建缓存时选用NSCache而非NSDictionary

在进行数据持久化缓存时,应该优先使用NSCache类来实现。NSCache相比NSDictionary具有自动删减、线程安全、不拷贝键的优势。

51.精简initialize与load的实现代码

load方法在代码被加载到代码区的时候调用,尽量不要在load方法中做复杂的工作,避免影响应用程序的启动速度。load方法和initialize方法中都应该避免对其他类的调用,避免加载或初始化时机差异导致的问题。未实现load方法的子类,即使父类实现了,也不会调用;未实现initialize方法的子类,会调用其父类的方法。

52.别忘了NSTimer会保留其目标对象

当创建一个Timer对象时,timer会保留其引用到的target对象,如果timer的模式是重复执行的,那么会有很大的可能产生循环引用。应该使用block的方式创建,或手动invalidate timer来避免内存泄露的问题.

《Effective Objective-C 2.0》全书的内容到这里就介绍完了,这本书非常全面的介绍了iOS开发中比较常遇到的问题或者需要规避的坑,还是非常有帮助的,有条件的读者建议自己买一本或借一本读一下,肯定会有不少收获!

之后会给大家带来一篇由iOS开发大牛唐巧撰写的《iOS开发进阶》的读书笔记,希望能给大家带来一些收获!敬请期待!
    原文作者:Coulson_Wang
    原文地址: https://www.jianshu.com/p/b8a7fc63bf11
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞