Texture的異步渲染和布局引擎

探討的幾個(gè)點(diǎn)

  • Texture的簡介 (What)
  • 為什么要使用Texture (Why)
  • Texture的作者 (Who)
  • Node的異步繪制如何實(shí)現(xiàn) (How)
  • Node的異步渲染(Runloop任務(wù)分發(fā))如何實(shí)現(xiàn) (How)
  • Texture的布局引擎 (How)
  • Texture的使用能帶來什么收益 (How Much)

texture簡介:

Texture(原名AsyncDisplayKit)是FaceBook開源的一款能夠保持界面流暢的框架冒冬。建立在UIKit之上菊匿,可以保持最復(fù)雜的用戶界面的流暢和響應(yīng)绍刮。(smooth and responsive)


1.x版本

2.x版本

Texture整體架構(gòu)

Texture

Node:對(duì)UIView和CALayer的抽象
Node Containers:node容器,負(fù)責(zé)加載渲染node
Layout Engineer:node布局

Texture節(jié)點(diǎn)容器與UIKit

節(jié)點(diǎn)容器

Texture節(jié)點(diǎn)子類與UIKit

節(jié)點(diǎn)子類

Texture節(jié)點(diǎn)子類繼承樹

繼承樹

為什么要使用Texture

  • 布局計(jì)算、解碼箕昭、繪制歌憨,異步并發(fā)執(zhí)行
  • Runloop任務(wù)分發(fā)(異步渲染)
  • 聲明式布局系統(tǒng)
  • 圖層預(yù)合成
  • 深度優(yōu)化列表性能(智能預(yù)加載)
Texture:圖層預(yù)合成

有時(shí)一個(gè) layer 會(huì)包含很多 sub-layer,而這些 sub-layer 并不需要響應(yīng)觸摸事件财饥,也不需要進(jìn)行動(dòng)畫和位置調(diào)整换吧。ASDK 為此實(shí)現(xiàn)了一個(gè)被稱為 pre-composing 的技術(shù),可以把這些 sub-layer 合成渲染為一張圖片钥星。開發(fā)時(shí)沾瓦,ASNode 已經(jīng)替代了 UIView 和 CALayer;直接使用各種 Node 控件并設(shè)置為 layer backed 后,ASNode 甚至可以通過預(yù)合成來避免創(chuàng)建內(nèi)部的 UIView 和 CALayer贯莺。

通過這種方式风喇,把一個(gè)大的層級(jí),通過一個(gè)大的繪制方法繪制到一張圖上乖篷,性能會(huì)獲得很大提升响驴。CPU 避免了創(chuàng)建 UIKit 對(duì)象的資源消耗,GPU 避免了多張 texture 合成和渲染的消耗撕蔼,更少的 bitmap 也意味著更少的內(nèi)存占用豁鲤。


圖層預(yù)合成1.png

圖層預(yù)合成2
Texture:智能預(yù)加載

所有節(jié)點(diǎn)都持有當(dāng)前界面狀態(tài)interfaceState,由ASRangeController控制屬性值更新鲸沮,在所有節(jié)點(diǎn)容器的內(nèi)部創(chuàng)建和維護(hù)琳骡。


智能預(yù)加載
  • Preload:節(jié)點(diǎn)還不可見,這時(shí)節(jié)點(diǎn)收集外部源(API或磁盤數(shù)據(jù))
  • Display:節(jié)點(diǎn)開始渲染讼溺,包括文本的光柵化以及圖像解碼等
  • Visible:節(jié)點(diǎn)可見楣号,在屏幕上至少擁有一個(gè)像素

Texture的作者

Scott Goodson

ASDK 的作者是 Scott Goodson ,他曾經(jīng)在蘋果工作怒坯,負(fù)責(zé) iOS 的一些內(nèi)置應(yīng)用的開發(fā)炫狱,比如股票、計(jì)算器剔猿、地圖视译、鐘表、設(shè)置归敬、Safari 等酷含,當(dāng)然他也參與了 UIKit framework 的開發(fā)。后來他加入 Facebook 后汪茧,負(fù)責(zé) Paper 的開發(fā)椅亚,創(chuàng)建并開源了 AsyncDisplayKit。目前他在 Pinterest 和 Instagram 負(fù)責(zé) iOS 開發(fā)和用戶體驗(yàn)的提升等工作舱污。

Node的異步繪制如何實(shí)現(xiàn)

UIKit的繪制機(jī)制圖解

CALayer的display方法由系統(tǒng)調(diào)用呀舔,用來更新layer的內(nèi)容,如果layer有delegate對(duì)象扩灯,那么display方法將嘗試調(diào)用delegate的displayLayer:方法來更新layer的內(nèi)容媚赖。如果delegate沒有實(shí)現(xiàn)displayLayer:方法,則這個(gè)方法會(huì)創(chuàng)建一個(gè)backing store來保存原來的內(nèi)容驴剔,然后調(diào)用layer的drawInContext:方法來填充back store省古。最后以新的backing store替換layer的先前內(nèi)容達(dá)到更新layer的目的。通常UIKit中CALayer的delegate是UIView對(duì)象丧失。

有兩種方式來自定義CALayer的內(nèi)容豺妓,一種是直接設(shè)置CALayer的contents屬性來創(chuàng)建寄宿圖;另一種是通過實(shí)現(xiàn)CALayer的delegate方法,可以用于直接對(duì)CALayer進(jìn)行操作琳拭。

Node的異步繪制

UIKit

Texture

ASDisplayNode是整個(gè)Texture的基石训堆,也是頁面異步繪制的核心,其持有UIView和CALayer兩種對(duì)象白嘁,均由node自己生成并管理坑鱼。


異步繪制時(shí)序圖

_ASDisplayLayer通過重寫了CALayer的display方法來自定義CALayer的寄宿圖屬性。_ASDisplayLayer與ASDisplayNode的關(guān)系類似于CALayer與UIView的關(guān)系絮缅。

Node的異步繪制流程

1.獲取node的displayBlock鲁沥,也就是負(fù)責(zé)根據(jù)node的視圖層級(jí)得到需要顯示的內(nèi)容的繪制任務(wù)。
2.生成Node繪制完成后的回調(diào)completeBlock耕魄。
3.根據(jù)displaysAsynchronously屬性來判斷是否需要異步繪制画恰,如果是異步的,則將displayBlock提交至_ASAsyncTransaction中吸奴,否則立即執(zhí)行displayBlock允扇。

tips

Node的異步渲染

1.尋找Layer相關(guān)的ASAsyncTransaction。
2.將displayBlock和completeBlock添加至ASAsyncTransaction则奥。
3.利用ASAsyncTransactionQueue進(jìn)行調(diào)度考润。
4.mainRunloop在開始sleep和exit的時(shí)候提交ASAsyncTransaction。
5.ASAsyncTransaction在提交的時(shí)候回調(diào)completeBlock读处,完成layer寄宿圖的賦值糊治。
<ps:displayBlock執(zhí)行不在主線程,completeBlock執(zhí)行在主線程!>

底層信號(hào)驅(qū)動(dòng)原理

信號(hào)驅(qū)動(dòng)

iOS的顯示系統(tǒng)由VSync信號(hào)驅(qū)動(dòng)的档泽,VSync信號(hào)由硬件時(shí)鐘生成俊戳,每秒鐘發(fā)出60次揖赴。iOS圖形服務(wù)接收到VSync信號(hào)后馆匿,會(huì)通過IPC通知到APP內(nèi)。APP的Runloop在啟動(dòng)后會(huì)注冊(cè)對(duì)應(yīng)CFRunloopSource通過mach_port接收傳過來的時(shí)鐘信號(hào)通知燥滑,隨后source的回調(diào)會(huì)驅(qū)動(dòng)整個(gè)App的動(dòng)畫與顯示渐北。

Runloop任務(wù)分發(fā) ->CoreAnimation

CA在Runloop中注冊(cè)了一個(gè)Observer,監(jiān)聽了BeforeWaiting和Exit事件铭拧,優(yōu)先級(jí)低于其他Observer赃蛛。當(dāng)一個(gè)觸摸事件到來時(shí),Runloop被喚醒搀菩,App中的代碼會(huì)執(zhí)行一些操作呕臂,比如創(chuàng)建和調(diào)整視圖層級(jí)、設(shè)置UIView的frame肪跋、修改CALayer的透明度歧蒋、為視圖添加一個(gè)動(dòng)畫;這些操作最終會(huì)被CALayer捕獲,并通過CATransaction提交到一個(gè)中間狀態(tài)去谜洽。當(dāng)上面的所有操作結(jié)束后萝映,Runloop即將進(jìn)入休眠(或者退出)時(shí),關(guān)注該事件的Observer都會(huì)得到通知阐虚。這時(shí)CA注冊(cè)的Observer就會(huì)在回調(diào)中序臂,把所有的中間狀態(tài)合并提交到GPU去顯示;如果此處有動(dòng)畫实束,CA會(huì)通過CADisplayLink等機(jī)制多次觸發(fā)相關(guān)流程奥秆。

Runloop任務(wù)分發(fā)->Texture

Texture在此處模擬了Core Animation的這個(gè)機(jī)制:所有針對(duì)ASNode的修改和提交,總有些任務(wù)是必須放入主線程執(zhí)行的咸灿。當(dāng)出現(xiàn)這種任務(wù)時(shí)吭练,ASNode會(huì)把任務(wù)用ASAsyncTransaction(Group)封裝并提交到一個(gè)全局的容器去。Texture也在Runloop中注冊(cè)了一個(gè)Observer析显,監(jiān)視的事件和CA一樣鲫咽,但優(yōu)先級(jí)比CA要低。當(dāng)Runloop進(jìn)入休眠前谷异、CA處理完事件后分尸,Texture就會(huì)執(zhí)行該loop內(nèi)提交的所有任務(wù)。通過這種機(jī)制歹嘹,Texture可以在合適的機(jī)會(huì)把異步箩绍、并發(fā)的操作同步到主線程去,并且能獲得不錯(cuò)的性能尺上。

Texture布局引擎

相對(duì)于AutoLayout

UIKit AutoLayout 在復(fù)雜的視圖結(jié)構(gòu)中材蛛,計(jì)算量會(huì)呈指數(shù)級(jí)增長,Texture的布局方案相對(duì)AutoLayout有以下優(yōu)點(diǎn):

  • 快:Texture的布局計(jì)算和手寫frame一樣快
  • 異步和并發(fā):布局可以在后臺(tái)線程上計(jì)算
  • 聲明式渲染:布局使用不可變的數(shù)據(jù)結(jié)構(gòu)聲明怎抛,實(shí)現(xiàn)一個(gè)layout視角從專注view之間的距離和約束卑吭,轉(zhuǎn)變成劃分和制定不同view子域的布局規(guī)則,抽象層級(jí)變高马绝,使得布局代碼更容易開發(fā)豆赏、維護(hù)
  • 可緩存:如果布局是不變的,自動(dòng)在后臺(tái)預(yù)先計(jì)算并緩存
  • 可拓展:在不同的類中使用相同的布局會(huì)變得很方便

Texture的布局系統(tǒng)

Texture自己定義了一套強(qiáng)大的automatic layout布局系統(tǒng)富稻,這套布局系統(tǒng)基于CSS的Box Model掷邦,通過提出LayoutSpec概念,使得我們可以通過聲明式的方法來定義布局椭赋。


layoutTable

<LayoutSpec> :一種特殊的layoutTable抚岗,與node不同的是,它本質(zhì)只是內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)哪怔,用以輔助view的位置計(jì)算宣蔚,繪制時(shí)不需要view來占位或者承載子元素廷痘。


布局系統(tǒng)

Texture布局規(guī)則&布局元素

  • 布局規(guī)則:充當(dāng)LayoutElements的容器,通過多個(gè)LayoutElements之間的關(guān)聯(lián)件已,完成LayoutElements的位置排列笋额,繼承自ASLayoutSpec。
  • 布局元素:所有的ASDisplayNode和ASLayoutSpec都遵守<ASLayoutElement>協(xié)議篷扩,可以通過兩個(gè)Nodes和其他的LayoutSpecs兄猩,生成或者組合一個(gè)新的LayoutSpecs。<ASLayoutElement>協(xié)議及LayoutSpecs有一些屬性用于創(chuàng)建非常復(fù)雜的布局鉴未。


    布局規(guī)則

Texture布局流程圖

布局流程

Texture布局示例

示例

Texture布局調(diào)試

在任何ASDisplayNode或ASLayoutSpec上調(diào)用-asciiArtString都會(huì)返回該對(duì)象及其子項(xiàng)的字符圖枢冤,也可以設(shè)置.debugName這樣也會(huì)包含在字符圖中。


調(diào)試

還可以在任何ASLayoutElement铜秆,比如Node和LayoutSpec上打印樣式對(duì)象淹真,調(diào)試.size屬性。


console

聲明式布局Demo鏈接:

https://ysw-hello@github.com/ysw-hello/TextureLayoutDemo.git

Texture所能帶來的收益

  • 異步繪制连茧、異步渲染通過Runloop任務(wù)分發(fā)核蘸,優(yōu)化復(fù)雜界面的主線程卡頓現(xiàn)象。
  • 圖層預(yù)合成啸驯、智能預(yù)加載的機(jī)制客扎,對(duì)列表進(jìn)行深度優(yōu)化,使得體驗(yàn)與性能得到進(jìn)一步的提升罚斗。
  • 聲明式布局方式徙鱼,F(xiàn)lexBox布局特點(diǎn),給iOS原生開發(fā)的布局模式帶來一種新的布局思維针姿,很新穎袱吆,很有特點(diǎn)。

Texture相關(guān)參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溉愁,一起剝皮案震驚了整個(gè)濱河市处铛,隨后出現(xiàn)的幾起案子饲趋,更是在濱河造成了極大的恐慌拐揭,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奕塑,死亡現(xiàn)場離奇詭異堂污,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)龄砰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門盟猖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讨衣,“玉大人,你說我怎么就攤上這事式镐》凑颍” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵娘汞,是天一觀的道長歹茶。 經(jīng)常有香客問我,道長你弦,這世上最難降的妖魔是什么惊豺? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮禽作,結(jié)果婚禮上尸昧,老公的妹妹穿的比我還像新娘。我一直安慰自己旷偿,他們只是感情好烹俗,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萍程,像睡著了一般衷蜓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尘喝,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天磁浇,我揣著相機(jī)與錄音,去河邊找鬼朽褪。 笑死置吓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缔赠。 我是一名探鬼主播衍锚,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼嗤堰!你這毒婦竟也來了戴质?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤踢匣,失蹤者是張志新(化名)和其女友劉穎告匠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體离唬,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡后专,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了输莺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戚哎。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡裸诽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出型凳,到底是詐尸還是另有隱情丈冬,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布甘畅,位于F島的核電站殷蛇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏橄浓。R本人自食惡果不足惜粒梦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荸实。 院中可真熱鬧匀们,春花似錦、人聲如沸准给。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽露氮。三九已至祖灰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間畔规,已是汗流浹背局扶。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留叁扫,地道東北人三妈。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像莫绣,于是被迫代替她去往敵國和親畴蒲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容