本文主要将Runloop原理与使用,所以其他文章中的内容可能有删减,我只放我觉得应该放入的内容,其他内容请看原文。
首先将引用文章的地址贴出来:深入理解Runloop Runloop使用场景二 runloop
runloop使用场景
1:与NSThread使用开启一个常驻线程,比如说afn。如果程序中,需要经常在子线程中执行任务,频繁的创建和销毁线程,会造成资源的浪费。 这时候我们就可以使用RunLoop来让该线程长时间存活而不被销毁。
启动一个runloop有以下三种方法:
- (void)run;
- (void)runUntilDate:(NSDate *)limitDate;
- (void)runMode:(NSString *)mode beforeDate:(NSDate*)limitDate;
这三种方式无论通过哪一种方式启动runloop,如果没有一个输入源或者timer附加于runloop上,runloop就会立刻退出。
(1) 第一种方式,runloop会一直运行下去,在此期间会处理来自输入源的数据,并且会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;
(2) 第二种方式,可以设置超时时间,在超时时间到达之前,runloop会一直运行,在此期间runloop会处理来自输入源的数据,并且也会在NSDefaultRunLoopMode模式下重复调用runMode:beforeDate:方法;
(3) 第三种方式,runloop会运行一次,超时时间到达或者第一个input source被处理,则runloop就会退出。
2:RunLoop保证NSTimer在视图滑动时,依然能正常运转。
当我们滑动scrollView时,主线程的RunLoop 会切换到UITrackingRunLoopMode这个Mode,执行的也是UITrackingRunLoopMode下的任务(Mode中的item),而timer 是添加在NSDefaultRunLoopMode下的,所以timer任务并不会执行,只有当UITrackingRunLoopMode的任务执行完毕,runloop切换到NSDefaultRunLoopMode后,才会继续执行timer。
我们只需要在添加timer 时,将mode 设置为NSRunLoopCommonModes即可。
NSRunLoopCommonModes并不是一种Mode,而是一种特殊的标记,包含三种mode(kCFRunLoopDefaultMode、NSTaskDeathCheckMode、UITrackingRunLoopMode),添加到NSRunLoopCommonModes中的还没有执行的任务,会在mode切换时,再次添加到当前的mode中,这样就能保证不管当前runloop切换到哪一个mode,任务都能正常执行。并且被添加到NSRunLoopCommonModes中的任务会存储在runloop 的commonModeItems中。
如果是在子线程中运行timer,那么将timer添加到RunLoop中后,Mode设置为NSDefaultRunLoopMode或NSRunLoopCommonModes均可,但是需要保证RunLoop在运行,且其中有任务。
3:滚动视图流畅性优化 参考的原文
然后在tableview滑动的时候,顺便打印出当前的runloopMode,可以看出,为imageView设置image,是在UITrackingRunLoopMode中进行的,如果图片很大,图片解压缩和渲染肯定会很耗时,那么卡顿就是必然的。
[imageView performSelector:@selector(setImage:) withObject:image afterDelay:0inModes:@[NSDefaultRunLoopMode]];
可以保证在滑动起来顺畅,可是停下来之后,渲染还未完成时,继续滑动就会变的卡顿。在切换到NSDefaultRunLoopMode中,一个runloop循环要解压和渲染18张大图,耗时肯定超过50ms(1/60s)。
我们可以继续来优化,一次runloop循环,仅渲染一张大图片,分18次来渲染,这样每一次runloop耗时就比较短了,滑动起来就会非常顺畅。这也是RunLoopWorkDistribution中的做法。
4:App卡顿监测 参考原文
网友评论