ios线程卡顿

作者: 赵永洪 | 来源:发表于2017-04-09 17:06 被阅读44次

    iOS设备虽然在硬件和软件层面一直在优化,但还是有不少坑会导致UI线程的卡顿。对于程序员来说,除了增加自身知识储备和养成良好的编程习惯之外,如果能一套机制能自动预报“卡顿”并检测出导致该“卡顿”的代码位置自然更好。本文就可能的实现方案做一些探讨和分析。先贴出最后方案的github地址

    解决方案分析

    简单来说,主线程为了达到接近60fps的绘制效率,不能在UI线程有单个超过(1/60s≈16ms)的计算任务。通过Instrument设置16ms的采样率可以检测出大部分这种费时的任务,但有以下缺点:

    Instrument profile一次重新编译,时间较长。

    只能针对特定的操作场景进行检测,要预先知道卡顿产生的场景。

    每次猜测,更改,再猜测再以此循环,需要重新profile。

    我们的目标方案是,检测能够自动发生,并不需要开发人员做任何预先配置或profile。运行时发现卡顿能即时通知开发人员导致卡顿的函数调用栈。

    基于上述前提,我暂时能想到两个方案大致可行。

    方案一:基于Runloop

    主线程绝大部分计算或者绘制任务都是以Runloop为单位发生。单次Runloop如果时长超过16ms,就会导致UI体验的卡顿。那如何检测单次Runloop的耗时呢?

    Runloop的生命周期及运行机制虽然不透明,但苹果提供了一些API去检测部分行为。我们可以通过如下代码监听Runloop每次进入的事件:

    - (void)setupRunloopObserver{staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{CFRunLoopRefrunloop =CFRunLoopGetCurrent();CFRunLoopObserverRefenterObserver;        enterObserver =CFRunLoopObserverCreate(CFAllocatorGetDefault(),                                              kCFRunLoopEntry | kCFRunLoopExit,true,-0x7FFFFFFF,                                              BBRunloopObserverCallBack,NULL);CFRunLoopAddObserver(runloop, enterObserver, kCFRunLoopCommonModes);CFRelease(enterObserver);    });}staticvoidBBRunloopObserverCallBack(CFRunLoopObserverRefobserver,CFRunLoopActivityactivity,void*info) {switch(activity) {casekCFRunLoopEntry: {NSLog(@"enter runloop...");        }break;casekCFRunLoopExit: {NSLog(@"leave runloop...");        }break;default:break;    }}

    相关文章

      网友评论

        本文标题:ios线程卡顿

        本文链接:https://www.haomeiwen.com/subject/nlgdattx.html