iOS runloop 学习笔记(三) - 彦祖叶孤城视频总结
彦祖谈runloop百度云地址:
链接: http://pan.baidu.com/s/1bpa9Lz5 密码: qgrc
彦祖视频中主要讲内容不是和前两篇文章一样的理论内容,主要是围绕如何在实际工作用用到 runloop,并且给了几个使用实例.
NSTimer 在 tracking mode 的应用
这个应用在前面笔记中都有提到,这里就不展开.
通过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.
具体的代码 Demo:
https://github.com/diwu/RunLoopWorkDistribution
当前有更好的图片相关性能优化的方法,这里只是提供了一种使用 RunLoop 进行优化的思路
runloop 监控 App 卡顿,并查找具体卡顿函数的方法
app 卡顿的定义
mainRunLoop 中一次 RunLoop 循环执行时间过长,导致新的事件传递到 RunLoop 中响应不及时, 直观感受就是卡顿.因此可以通过一定方法求出,第一次进入 RunLoop 与第二次进入 RunLoop 之间的时间, 如果这个时间超过某阀值,就说明 App 卡顿.
具体实践
使用 global 线程中监听 mainRunLoop 的状态, 使用使用 semaphore 来进行超时统计(超时时间就是 runloop 的阀值)管理. 如果连续多次超时,就使用 CrashReport 打印出当前函数调用栈的内容.
具体的代码 Demo:
https://github.com/suifengqjn/PerformanceMonitor
Demo 地址中也对源码有相应的解释
ps 最后还有一篇非常好的文章:
yy 大神的笔记: http://blog.ibireme.com/2015/05/18/runloop/