前言
本文的中文注釋代碼demo更新在我的github上。
AsyncDisplayKit 是 Facebook 開源的一個(gè)用于保持 iOS 界面流暢的框架。主要作者是 Scott Goodson(github)蛉迹。
本文主要是從理論和源代碼角度分析一下整個(gè)ASDK庫姑隅,其中參考了很多參考資料中的內(nèi)容得滤,加以整理和復(fù)習(xí)盐肃。
發(fā)展歷史
AsyncDisplayKit(ASDK)是2012年由Facebook開始著手開發(fā),并于2014年出品的高性能顯示類庫号枕,主要作者是Scott Goodson缰揪。Scott曾經(jīng)參與了多個(gè)iOS版本系統(tǒng)的開發(fā),包括UIKit以及一些系統(tǒng)原生app葱淳,后來加入Facebook并參與了ASDK的開發(fā)并應(yīng)用到Paper钝腺,因此該庫有機(jī)會(huì)從相對(duì)底層的角度來進(jìn)行一系列的優(yōu)化。
想要了解 ASDK 的原理和細(xì)節(jié)赞厕,最好從下面幾個(gè)視頻開始:
- 2014.10.15 NSLondon - Scott Goodson - Behind AsyncDisplayKit
- 2015.03.02 MCE 2015 - Scott Goodson - Effortless Responsiveness with AsyncDisplayKit
- 2015.10.25 AsyncDisplayKit 2.0: Intelligent User Interfaces - NSSpain 2015
解決的問題
很多時(shí)候用戶在操作app的時(shí)候艳狐,會(huì)感覺到不適那么流暢,有所卡頓皿桑。
ASDK主要就是解決的問題就是操作頁面過程中的保持幀率在60fps(理想狀態(tài)下)的問題毫目。
造成卡頓的原因有很多蔬啡,總結(jié)一句話基本上就是:
CPU或GPU消耗過大,導(dǎo)致在一次同步信號(hào)之間沒有準(zhǔn)備完成镀虐,沒有內(nèi)容提交箱蟆,導(dǎo)致掉幀的問題。
具體的原理刮便,在提升 iOS 界面的渲染性能文章中介紹的十分詳細(xì)了空猜,這里也不多闡述了。
優(yōu)化原理
從ASDK的視頻與tutorial上恨旱,可以整理出三個(gè)ASDK主要優(yōu)化的方面:
-
布局:
iOS自帶的Autolayout在布局性能上存在瓶頸辈毯,并且只能在主線程進(jìn)行計(jì)算。(參考Auto Layout Performance on iOS)因此ASDK棄用了Autolayout窖杀,自己參考自家的ComponentKit設(shè)計(jì)了一套布局方式。 -
渲染
對(duì)于大量文本裙士,圖片等的渲染入客,UIKit組件只能在主線程并且可能會(huì)造成GPU繪制的資源緊張。ASDK使用了一些方法腿椎,比如圖層的預(yù)混合等桌硫,并且異步的在后臺(tái)繪制圖層,不阻塞主線程的運(yùn)行啃炸。 -
系統(tǒng)對(duì)象創(chuàng)建于銷毀
UIKit組件封裝了CALayer圖層的對(duì)象铆隘,在創(chuàng)建、調(diào)整南用、銷毀的時(shí)候膀钠,都會(huì)在主線程消耗資源。ASDK自己設(shè)計(jì)了一套Node機(jī)制裹虫,也能夠調(diào)用肿嘲。
**實(shí)際上,從上面的一些解釋也可以看出筑公,ASDK最大的特點(diǎn)就是"異步"雳窟。
將消耗時(shí)間的渲染、圖片解碼匣屡、布局以及其它 UI 操作等等全部移出主線程封救,這樣主線程就可以對(duì)用戶的操作及時(shí)做出反應(yīng),來達(dá)到流暢運(yùn)行的目的捣作。
**
ASDisplayNode的整體設(shè)計(jì)
AsyncDisplayKit’s basic unit is the node. ASDisplayNode is an abstraction over UIView, which in turn is an abstraction over CALayer. Unlike views, which can only be used on the main thread, nodes are thread-safe: you can instantiate and configure entire hierarchies of them in parallel on background threads.
這段是ASDK官網(wǎng)上的原話誉结。可以看出ASDK的核心就是ASDisplayNode券躁。在介紹ASDisplayNode前搓彻,需要介紹一下目前UIView于CALayer的關(guān)系如绸。
UIView與CALayer的關(guān)系:
UIView持有CALayer,顯示依靠CALayer旭贬。
CALayer的delegate是UIView怔接,可以回調(diào)通知UIView的變化。
UIView 和 CALayer 都不是線程安全的稀轨,并且只能在主線程創(chuàng)建扼脐、訪問和銷毀。
ASDisplayNode
ASNode(ASDisplayNode以下同)仿照這樣的關(guān)系奋刽,通過view去持有UIView瓦侮,并且讓UIView通過.node回調(diào)自己。在ASNode中封裝了常見的視圖屬性佣谐,讓開發(fā)者直接去調(diào)用ASNode進(jìn)行開發(fā)肚吏。
并且ASNode可以設(shè)置layer backed屬性,就是不需要響應(yīng)觸摸事件狭魂。這時(shí)候ASNode將直接操作CALayer進(jìn)行顯示罚攀,更加優(yōu)化了性能。
ASNode本身是線程安全的雌澄,所以它允許在后臺(tái)線程進(jìn)行創(chuàng)建和修改斋泄。
這里借用一下提升 iOS 界面的渲染性能中的一段話:
Node 剛創(chuàng)建時(shí),并不會(huì)在內(nèi)部新建 UIView 和 CALayer镐牺,直到第一次在主線程訪問 view 或 layer 屬性時(shí)炫掐,它才會(huì)在內(nèi)部生成對(duì)應(yīng)的對(duì)象。當(dāng)它的屬性(比如frame/transform)改變后睬涧,它并不會(huì)立刻同步到其持有的 view 或 layer 去募胃,而是把被改變的屬性保存到內(nèi)部的一個(gè)中間變量,稍后在需要時(shí)畦浓,再通過某個(gè)機(jī)制一次性設(shè)置到內(nèi)部的 view 或 layer摔认。
ASDK整體提供了十分多的Node組件,比如Button,Cell等等宅粥,利用這些組件参袱,開發(fā)者可以繞過UIKit進(jìn)行開發(fā)。這里貼一張官網(wǎng)上的層級(jí)圖
渲染過程
ASDisplayNode的渲染過程主要有以下幾步:
- 初始化ASDisplayNode對(duì)應(yīng)的 UIView 或者 CALayer
- 在當(dāng)前視圖進(jìn)入視圖層級(jí)時(shí)執(zhí)行 setNeedsDisplay秽梅;
- display 方法執(zhí)行時(shí)抹蚀,向后臺(tái)線程派發(fā)繪制事務(wù);
- 在Runloop中注冊(cè)observer企垦,在每個(gè) RunLoop 結(jié)束時(shí)回調(diào)环壤。
這邊的細(xì)化會(huì)在之后介紹源代碼的時(shí)候介紹。
其他內(nèi)容
ASDK還包含以下內(nèi)容:
- ASLayout的布局功能
- ASAsyncTransaction的異步繪制控制
- ASViewController結(jié)點(diǎn)容器
- ASTableView/ASCollectionView以及對(duì)應(yīng)的控制器ASRangeController/ASDataController
總結(jié)
本文大體上介紹了一下AsyncDisplayKit的整體流程和優(yōu)化方法钞诡,之后的幾章將從源代碼角度去分析ASDK的渲染過程郑现。
參考資料
本文csdn地址
1.AsyncDisplayKit源碼分析
2.AsyncDisplayKit介紹
3.提升 iOS 界面的渲染性能
4.iOS 保持界面流暢的技巧
5.AsyncDisplayKit Getting Started
6.AsyncDisplayKit Tutorial: Node Hierarchies