一、UITrackingRunLoopMode与NSTimer
下面的方法Timer被添加到NSDefaultRunLoopMode,在滑动Scrollview的时候系统会切换至UITrackingRunLoopMode,Timer就会暂时停止.
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];
当存在 tableView/scrollView 滑动时,若不希望Timer被滑动影响,需添加到NSRunLoopCommonMode.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:timer forMode:NSRunLoopCommonModes];
二、通过runloop解决在 tableView 滚动时候停止加载图片的需求
利用RunLoop 不同 mode 的特性,可以将图片的加载放到NSDefaultRunLoopMode的mode里,这样在滚动UITrackingRunLoopMode这个mode时不会被加载而影响到。
UIImage *downloadedImage = ...;
[self.avatarImageView performSelector:@selector(setImage:) withObject:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]];
三、runloop 解决在 tableView 中同时加载多个大图的使用
runloop 中最先响应的 UI 的绘制, tableView 在滑动时就需要在一次 runloop 循环中绘制所有的屏幕上的图片,如果在 cellForxxx 方法中有imageView.image = image 等代码,这部分会非常消耗资源(尤其在图片较大的情况),一次 runloop 执行时间太长, 就会导致 UI 响应变慢, 直观感受就是 app 卡顿严重.
解决思路
原来是一次runloop 中绘制所有的 view 中显示出来的图片,那么为什么不在一次 runloop 时候只绘制一张图片. 这样每次 runloop 需要完成的内容较少,UI 才不会卡顿.
具体实践
首先封装一个task queue,用它观察 RunLoop 的状态, 当 RunLoop 的状态是 kCFRunLoopBeforeWaiting,取出 queue 中的第一个 task 然后执行,然后将该 task 移除 queue. queue 中的 task 是一个个将耗时任务封装的成的代码块. 在 tableView 的 cellForRowAtIndexPath 方法中,我们将 task 代码块加入到 queue 中,让 queue 根据 RunLoop 的状态每次在进入睡眠前执行一个 task.
https://github.com/diwu/RunLoopWorkDistribution
四、runloop 监控 App 卡顿,并查找具体卡顿函数的方法
app 卡顿的定义
mainRunLoop 中一次 RunLoop 循环执行时间过长,导致新的事件传递到 RunLoop 中响应不及时, 直观感受就是卡顿.因此可以通过一定方法求出,第一次进入 RunLoop 与第二次进入 RunLoop 之间的时间, 如果这个时间超过某阀值,就说明 App 卡顿.
具体实践
使用 global 线程中监听 mainRunLoop 的状态, 使用使用 semaphore 来进行超时统计(超时时间就是 runloop 的阀值)管理. 如果连续多次超时,就使用 CrashReport 打印出当前函数调用栈的内容.
https://github.com/suifengqjn/PerformanceMonitor
还在学习中,不足之处,请谅解!
本文转自http://www.jianshu.com/p/924cb2b218f5