内存警告的处理
1、首先需要检查循环应用的问题
① 设置代理时注意要使用弱引用。
② block使用时,函数内部涉及到外部的引用需要用weak修饰来打破环。但是用weak修饰也有缺陷,如果block内部是延时操作或者说异步操作,很有可能在使用数据的时候,数据的内存就已经被回收了,怎么解决呢?我们放到后面讲。
③ NSTimer的使用
2、大量的变量占据了较大内存
需要放到@autoreleasepool自动释放池。
3、清除不需要的视图
清除前判断视图已经被创建了 && 视图没有出现在window上,就可以清除了。还有当前vc中的一些变量都可以置空,不过前提是要记得用懒加载,这样在置空后还可以加载回来
4、applicationDidReceiveMemoryWarning
在AppDelegate的applicationDidReceiveMemoryWarning可以做一些全局的处理,比方说一些单例可以直接置空.
5、检查有使用图片的code
不要给用户展示过大的原图,如果一定要展示使用imageWithContentsOfFile(仅加载图片,不缓存),在展示后手动置空。如果使用了SDWebImageView,也可以通过置空sharedImageCache缓存在内存的图片
6、野指针的检查(僵尸对象)
7、销毁持有大量对象的容器类变量
在后台销毁该类型对象,销毁方法:将要销毁的对象捕获到block中,放到异步的后台队列随便发个消息来避免警告,就可以让对象在后台销毁了
定时器的应用
NSTimer使用注意事项
- 说明:NSTimer设置target = self并且是反复使用的时候,很容易和当前类形成循环引用,在不使用的时候,记得注销计时器后赋值为nil,但是这个很难保证他人使用自己的类会记得,因此我们可以提前做一下处理。
** 在dealloc时invalidate是无效的,因为如果出现循环引用,该viewcontroller是不会进入到dealloc阶段,所以也无法注销该计时器 ** - 特殊情况:在iOS10后可以调用scheduledTimerWithTimeInterval:repeats:blocks来实现.使用上面方法的时候要注意先定义一个弱引用weakSelf指向self (__weak typeOf(self)weakSelf = self),但是在block使用weakSelf有个问题,这个self不会为计数器保留,而且有可能在self内存回收后才执行,这就会引起报错了。所以我们在块开始执行时,立即生成strong引用(MyObject *strongSelf = weakSelf)那在iOS10以前要怎么处理呢?我们可以为NSTimer写个分类,在@seletor()里面实现block的调用方法,block作为参数在userInfo传递过去
- 优势:能够继承使用,比较灵活
- 弊端:依托于RunLoop,准确性容易受RunLoop影响,同时也容易造成内存泄漏
CADisplayLink
- 优势:根据屏幕刷新帧率来触发事件,因此时间是比较准确的一种计时器,适合做UI刷新的工作,过渡比较顺滑
- 劣势:Selector事件如果大于间隔时间,容易导致掉帧;不能被继承使用;事件处理的间隔只能是屏幕刷新间隔的倍数;如果CPU负荷太大,会影响到屏幕刷新的帧率,从而影响事件的调用
dispatch_source_t
- 说明:这是GCD的一个源对象,使用的时候必须设置为成员变量,否则会在创建后立刻释放。GCD创建的Timer如果处于suspend挂起状态,需要resume才能cancel,否则容易造成内存泄漏。
- 劣势:虽然不受RunLoop影响,但是如果有其他事件阻塞了全部的线程,也会影响该计时器
** PS:记得block传参时要声明copy,理由不在这里讲了。*
Method Swizzling应该在+load()还是+initialize()执行,并说明理由
应该在+load()执行。
+load()是在类初始化加载的时候就会调用,+initialize()则是在第一次调用该类的类方法或者生成实例的时候调用,前者比后者要先执行。由于Method Swizzling是会影响全局的状态,并且这个操作不是原子性的,因此最小竞争的条件就尤其重要,在+load()就能避免很多问题。但是在执行+load()的时候,应用的线程是阻塞的,这也是为什么Method Swizzling要尽可能少用的原因。
网友评论