影響APP的底層機(jī)制阳欲,主要是CPU舵盈,GPU的占用率和 內(nèi)存的使用率,
APP主線程在CPU中胸完,計(jì)算顯示內(nèi)容书释,比如視圖的創(chuàng)建,布局赊窥,圖片解碼爆惧,文件繪制等,計(jì)算完這些東西后交給GPU把結(jié)果提交到幀緩沖區(qū)去锨能,等待下一次 垂直 信號(hào)到來時(shí)顯示到屏幕上扯再。由于垂直同步的機(jī)制,如果在一個(gè) VSync 時(shí)間內(nèi)址遇,CPU 或者 GPU 沒有完成內(nèi)容提交熄阻,則那一幀就會(huì)被丟棄,等待下一次機(jī)會(huì)再顯示倔约,而這時(shí)顯示屏?xí)A糁暗膬?nèi)容不變秃殉。這就是界面卡頓的原因。
無論是CPU或GPU哪個(gè)阻礙了顯示的流程都會(huì)造成掉幀的現(xiàn)象浸剩,在xcode里面也可以看到手機(jī)APP在調(diào)試模式下CPU和內(nèi)存的使用情況钾军。
一 CPU方面
從三個(gè)打的方面考慮,對(duì)象的創(chuàng)建绢要,調(diào)整和銷毀都會(huì)影響CPU的使用
對(duì)象的創(chuàng)建如果不處理事件吏恭,盡量使用輕量級(jí)的CALayer,xib或Storyboard會(huì)是這些創(chuàng)建的消耗大很多重罪,經(jīng)常使用的對(duì)象應(yīng)該放到緩存里面重復(fù)利用樱哼,UIImage imageNamed適合重復(fù)使用的對(duì)象,initWithContentOfFile適合一次性使用的對(duì)象剿配。
CALayer并不能夠直接調(diào)整視圖的屬性搅幅,而是通過runtime,resolveInstanceMethod為對(duì)象臨時(shí)添加一個(gè)方法呼胚,同時(shí)把對(duì)象的屬性保存在一個(gè)字典里面盏筐,然后發(fā)送通知給代理,創(chuàng)建動(dòng)畫砸讳,UIView是CALayer的包裝琢融,對(duì)對(duì)象的屬性調(diào)整時(shí)大于一般對(duì)象的屬性界牡,應(yīng)該有immutable 的思想,另外重寫drawreact方法也會(huì)帶來很大性能的損耗漾抬,盡量避免視圖層次過多的疊加和變動(dòng)宿亡。React 有類似的思想,利用高效的算法纳令,對(duì)比當(dāng)前視圖和之前視圖的差異挽荠,然后做調(diào)整,當(dāng)在移動(dòng)開發(fā)時(shí)平绩,
React Native的效果和原生的還是有一定的差距圈匆,特別是動(dòng)畫的使用上,做頻繁的變動(dòng)導(dǎo)致掉幀率變大捏雌。導(dǎo)航視圖移動(dòng)過慢跃赚。
對(duì)象的銷毀一般是在主線程里面來進(jìn)行的,也可以單獨(dú)的放到后臺(tái)線程里面進(jìn)行性湿。對(duì)應(yīng)大量使用循環(huán)對(duì)象纬傲,可以使用autoreleasePool來管理。
對(duì)應(yīng)布局的技術(shù)和調(diào)整肤频,可以考慮用空間換時(shí)間的方式叹括,讓服務(wù)器返回圖片的大小,避免默認(rèn)圖的固定大小造成的tableview刷新過多宵荒,盡量緩存tableview的高度汁雷,重復(fù)使用,對(duì)應(yīng)復(fù)雜的視圖报咳,可以考慮用串行隊(duì)列侠讯,將對(duì)象的創(chuàng)建和push的動(dòng)作隔離開來,可以明顯的增加視圖的加載效率少孝,盡量使用后臺(tái)計(jì)算視圖的顯示數(shù)據(jù)
autolayout等技術(shù)使用在復(fù)雜布局上時(shí)继低,會(huì)產(chǎn)生嚴(yán)重的性能問題熬苍,應(yīng)該避免使用稍走,可以考慮ComponentKit、AsyncDisplayKit 柴底,EZayout等框架婿脸,
對(duì)于文本的計(jì)算,可以使用coretext排版可以直接獲取文本的高度柄驻,把計(jì)算高度的工作交給后臺(tái)狐树,coretext對(duì)象可以重復(fù)使用。
對(duì)應(yīng)圖片的繪制鸿脓,可以使用CoreGraphic獲取bitmap抑钟,用ImageIO直接解壓圖片
二 GPU方面
GPU 能干的事情比較單一:接收提交的紋理(Texture)和頂點(diǎn)描述(三角形)涯曲,應(yīng)用變換(transform)、混合并渲染在塔,然后輸出到屏幕上幻件。通常你所能看到的內(nèi)容,主要也就是紋理(圖片)和形狀(三角模擬的矢量圖形)兩類蛔溃。
超大圖片的使用會(huì)導(dǎo)致內(nèi)存的暴漲绰沥,可以使用GPU加速的layer控制。
申明透明的view opaque 為1
CALayer 的 border贺待、圓角徽曲、陰影、遮罩(mask)麸塞,CASharpLayer 的矢量圖形顯示秃臣,通常會(huì)觸發(fā)離屏渲染(offscreen rendering),而離屏渲染通常發(fā)生在 GPU 中喘垂。當(dāng)一個(gè)列表視圖中出現(xiàn)大量圓角的 CALayer甜刻,并且快速滑動(dòng)時(shí),可以觀察到 GPU 資源已經(jīng)占滿正勒,而 CPU 資源消耗很少得院。這時(shí)界面仍然能正常滑動(dòng)章贞,但平均幀數(shù)會(huì)降到很低祥绞。為了避免這種情況,可以嘗試開啟 CALayer.shouldRasterize 屬性鸭限,但這會(huì)把原本離屏渲染的操作轉(zhuǎn)嫁到 CPU 上去蜕径。對(duì)于只需要圓角的某些場(chǎng)合,也可以用一張已經(jīng)繪制好的圓角圖片覆蓋到原本視圖上面來模擬相同的視覺效果败京。最徹底的解決辦法兜喻,就是把需要顯示的圖形在后臺(tái)線程繪制為圖片,避免使用圓角赡麦、陰影朴皆、遮罩等屬性》捍猓可以考慮用畫圖的方式截取圓角遂铡。
比較高效的開源庫有AsyncDisplayKit,擁有高效的異步繪制和渲染能力晶姊,最后扒接,用 Instuments 的 GPU Driver 預(yù)設(shè),能夠?qū)崟r(shí)查看到 CPU 和 GPU 的資源消耗。在這個(gè)預(yù)設(shè)內(nèi)钾怔,你能查看到幾乎所有與顯示有關(guān)的數(shù)據(jù)碱呼,比如 Texture 數(shù)量、CA 提交的頻率宗侦、GPU 消耗等巍举,在定位界面卡頓的問題時(shí),這是最好的工具凝垛。如果界面出現(xiàn)不明卡頓懊悯,可以監(jiān)聽主線程的runloop,監(jiān)控到了卡頓現(xiàn)場(chǎng),PLCrashReporter,它不僅可以收集Crash信息也可用于實(shí)時(shí)獲取各線程的調(diào)用堆棧(http://www.tanhao.me/code/151113.html/)