Effective Objective-C 2.0 读书笔记
最近这本书的1刷已经结束了,然后回过头来看首先是觉得理解的不够深入,其次是拓展的不够宽泛,所以总结一下,把核心的东西抽出来便于理解。
1刷是电子书,刷到末期的时候,直接买了实体书,二刷还是看实体书吧。
Tip:50 构建缓存时选用NSCache而非NSDictionary
应用场景:下载图片的后,把内存中的图片保留下来,以便稍后再用。
NSCache的优点:
- 系统发出低内存通知的时候,依据最久未使用(LRU)自动删减存储在其中的对象。
- 是线程安全的,
- 通过改变NSCache属性中的缓存对象的个数,以及指定缓存空间的大小(开销),当对象总数或者总开销超过上限的时候缓存就可能会删除其中的对象。
NSPurgeableData:
适用范围解读
如果某个对象所占的内存可以随时丢弃,就可以用这个。
也就是说,这个类可以把对象标记为<必要时可以丢弃自己所占的内存>
实现原理
实现了NSDiscardableContent协议,这个协议的作用是让实现该协议所定义的接口
的对象的内存能够根据需要随时丢弃。
使用方法
//需要访问的时候,调用如下方法,告诉其还不应该丢弃自己所占的内存
[cacheData beginContentAccess];
//使用完之后,调用如下方法,告诉其必要的时候可以丢弃内存
[cacheData endContentAccess];
/*类似引用计数成对出现,创建NSPurgeableData的操作也会被视为'引用计数+1'*/
Tip:51 精简initialize 与 load 的实现代码
首先这两个方法是属于NSObject的,可以用来实现初始化操作。
load
调用时机:当类和分类加入运行期系统的时候。【程序会阻塞等所有类load执行完才继续】
执行顺序:在执行子类之前,先执行超类的Load方法,如果有其他依赖库,那他们的load方法也会执行(无法判断类的载入顺序)
特点:不遵循继承规则。就是说超类实现load方法,子类如果没有实现load,系统就不会调用load方法。类的load要比分类的load先执行。
注意事项:程序在执行load方法时都会阻塞,【不要】在load中执行任何的任务。
用途:【调试】,在分类中编写次方法,判断分类是否正确载入系统。
initlalize
调用时机:程序首次用该类之前调用,只调用一次。不要手动调用(它是由运行期系统调用的)
执行顺序:执行的时候,运行期系统处于正常状态(应该讲的是所有类都已经加载到运行期系统中),然后可以在其中安全的调用任意类的任意方法。
安全性:initlalize是线程安全的。执行它的时候,其他想要操作initlalize所在类的其他线程都会阻塞等其initlalize执行完。
特点:遵循继承规则,子类会实现父类的initlalize方法。
总结
- 初始化方法里面仅仅适合设置一些状态,不适合执行复杂&加锁的任务。
- 初始化类的线程是随机的。当时UI线程时,初始化期间就会一直阻塞导致应用程序无响应。
- 无法控制类的初始化时机,也不能令初始化依赖特定的时间点。(万一运行期系统略微调整,那代码就失效了)
- 当在初始化方法中(直接或间接)使用到其他类的时候,其他类的initlalize方法中需要用到本类的数据,但是本类的initlalize方法还没运行完毕,数据可能还没准备好。
应用
initlalize方法只应该用来设置内部数据。
比如说某个全局状态无法在编译期间初始化。
point:整数可以在编译期定义,可变数组对象不可以(NSString是可以的),所以创建期间必须先激活运行期系统。也就是说让运行期系统处于【安全期状态】
所以可以在initlalize方法中初始化全局的可变数组,代码如下
static NSMutableArray *kSomeObjects;
@implementation MyClass
+ (void)initlalize{
//只在当前类初始化,因为initlalize遵循继承规则,会被子类调用,所以要加个判断,让代码在本类执行。
if(self == [MyClass class]){
kSomeObjects = [NSMutableArray new];
}
}
Tip:52 别忘了NSTimer会保留其目标对象。
基础知识:
- 计时器要和RunLoop相关联,Runloop到了设定的时间会出发任务。
- NSTimer会保留其目标对象,等到自身实现的时候再释放。
- 一次性的定时器任务结束的时候失效,重复执行的要手动调用invalidate方法使其失效。
出现保留环的情况:当没有显示调用invalidate方法时,就把使用定时器的类释放了。这时候NSTimer作为所在类的实例对象,会被类强引用。而且本类作为NSTimer的target也会被NSTimer强引用。因此出现循环引用的情况。
解决方案:为NSTimer添加一个类方法,通过Block创建NSTimer对象。
userInfo中可以存储任意类型,因为我们要在回调方法中调用block,但是分类不容易添加属性,所以就把block拷贝后放到userInfo中,然后在回调方法的参数中取出block来调用。
新的方式:对于调用此方法创建的NSTimer的时候,就可以通过传入weakSelf 的方式,来打破block的循环引用了。
Q&A
Q:分类中,block方式创建NSTimer的方法体中不是会强引用NSTimer类对象么?
A:NSTimer类对象是个单例,计时器是否会保留它都无所谓。因为类对象无需回收。