一、卡頓問(wèn)題的幾種原因
復(fù)雜 UI 、圖文混排的繪制量過(guò)大;
在主線程上做網(wǎng)絡(luò)同步請(qǐng)求;
在主線程做大量的 IO 操作;
運(yùn)算量過(guò)大,CPU 持續(xù)高占用;
死鎖和主子線程搶鎖。
二、監(jiān)測(cè)卡頓的思路
監(jiān)測(cè)FPS:
FPS 是一秒顯示的幀數(shù),也就是一秒內(nèi)畫面變化數(shù)量。如果按照動(dòng)畫片來(lái)說(shuō),動(dòng)畫片的 FPS 就是 24,是達(dá)不到 60 滿幀的。也就是說(shuō),對(duì)于動(dòng)畫片來(lái)說(shuō),24 幀時(shí)雖然沒有 60 幀時(shí)流暢,但也已經(jīng)是連貫的了,所以并不能說(shuō) 24 幀時(shí)就算是卡住了。 由此可見,簡(jiǎn)單地通過(guò)監(jiān)視 FPS 是很難確定是否會(huì)出現(xiàn)卡頓問(wèn)題了,所以我就果斷棄了通過(guò)監(jiān)視 FPS 來(lái)監(jiān)控卡頓的方案。
RunLoop:
通過(guò)監(jiān)控 RunLoop 的狀態(tài)來(lái)判斷是否會(huì)出現(xiàn)卡頓。RunLoop原理這里就不再多說(shuō),主要說(shuō)方法,首先明確loop的狀態(tài)有六個(gè)

我們需要監(jiān)測(cè)的狀態(tài)有兩個(gè):RunLoop 在進(jìn)入睡眠之前和喚醒后的兩個(gè) loop 狀態(tài)定義的值,分別是 kCFRunLoopBeforeSources 和 kCFRunLoopAfterWaiting ,也就是要觸發(fā) Source0 回調(diào)和接收 mach_port 消息兩個(gè)狀態(tài)。
三、如何檢查卡頓
說(shuō)下步驟:
創(chuàng)建一個(gè) CFRunLoopObserverContext 觀察者;
將創(chuàng)建好的觀察者 runLoopObserver 添加到主線程 RunLoop 的 common 模式下觀察;
創(chuàng)建一個(gè)持續(xù)的子線程專門用來(lái)監(jiān)控主線程的 RunLoop 狀態(tài);
一旦發(fā)現(xiàn)進(jìn)入睡眠前的 kCFRunLoopBeforeSources 狀態(tài),或者喚醒后的狀態(tài) kCFRunLoopAfterWaiting,在設(shè)置的時(shí)間閾值內(nèi)一直沒有變化,即可判定為卡頓;
dump 出堆棧的信息,從而進(jìn)一步分析出具體是哪個(gè)方法的執(zhí)行時(shí)間過(guò)長(zhǎng)



