AsyncDisplayKit原始碼分析(一)輪廓梳理

折騰範兒_味精發表於2017-12-13

遷移一批老文章到掘金 本文(二)太監了╮(╯_╰)╭

本篇文章的全文可以用另一個文章標題來概括!

我們為什麼壓根不應該使用AsyncDisplayKit

而我的非同步繪製的後面那一篇文章也可以用另一個文章標題來概括!

不用AsyncDisplayKit,我們怎麼非同步繪製

前言

Facebook出得這個AsyncDisplayKit嚴格意義上講,已經遠遠超出了超出了AsyncDisplay的範圍.

我個人在最開始思考AsyncDisplay的時候,以為這只是一個解決非同步渲染的問題,可能是最大限度的在layer層display的時候做文章,直到我粗略了學習了下他的原始碼,才發現,我只看到了ASDK中很小很小很小的一塊。

ASDK其實已經十分龐大,涵蓋了AsyncQueueControl(非同步佇列控制),在佇列控制基礎上封裝的AsyncDisplay(非同步繪製),AsyncLayout(非同步UI佈局計算),AsyncFetchData(非同步資料準備),AsyncTextLayout(非同步文字排版)並且又在此之上,重寫了一整套幾乎我們能用到的所有UIKit控制元件,小到ImageView,Button,Text,大到Tableview,CollectionView,再到ViewController,全都一一對應重寫了一套ASDK的ASXXNode

因此,使用ASDK的開發者,面臨的最大問題是,雖然ASDK各方面的用法都是儘可能做到很像UIKit的,並且支援相容從舊的UIKit生成新的ASNode,但是如果想使用ASDK,勢必得完全改變以前的編碼習慣,以前的舊程式碼,再開發UI的時候,完全使用ASXX開頭的控制元件,放棄蘋果官方的frame佈局,或者官方的autolayout,轉而使用ASDK的layout方案(支援自己擴充套件),如果涉及文字,也要使用ASText相關的富文字描述(支援自己擴充套件),如果涉及Tableview CollectionView,甚至寫代理的習慣都要跟著改變和適應

對於我們來說,想要引入ASDK,確實太重了,我們不妨把它當做一個學習樣本,去拆解分析一下這裡面是如何運作的

AsyncDisplayKit 輪廓梳理

核心基礎ASDisplayNode

就好像所有的UIKit最重都是從UIView繼承一樣,ASDisplayNode就是整個AsyncDisplayKit的基石,幾乎所有的AS物件都是從ASDisplayNode繼承出來(ASViewController,ASRangeController,ASDataController等例外)

ASNode

此圖是官網一個截圖,便於我們去進行類比理解 ASDisplayNode VS UIView

CALayer

  • CALayer專注負責一切關於渲染繪製的事情
  • CALayer只能在主執行緒使用

UIView

  • UIView內部持有了CALayer,將layer封裝起來
  • UIView充當CALayer的delegate,渲染動畫時產生的時間會通知view
  • UIView可以通過.layer直接訪問CALayer,從而更進一步操作渲染
  • UIView管理著CALayer的渲染,同時還管理著其他諸如點選事件等渲染之外的事情
  • UIView只能在主執行緒使用

ASDisplayNode

  • ASDisplayNode內部持有了UIView,將view封裝起來
  • ASDisplayNode充當UIView的delegate,原本view產生的各種事件,由於已經不直接操作UIView,因此會delegate通知node進行處理
  • ASDiplayNode可以通過.view直接訪問UIView
  • ASDiplayNode管理著UIView,接管了UIView的一些處理操作
  • ASDiplayNode通過對非同步處理的改造,讓使用者可以在安全的線上程進行操作

ASNode的控制元件繼承結構

可以看看ASXXNode系列,都有哪些,下圖裡面並沒有舉例完所有的public ASNode,只是粗略列出常用的

asnodetree

是不是很像,UIView->UIControl->UIButton的UIKit繼承結構

ASDK的容器

每一個Node節點是可以直接通過UIView的addSubnode方法新增到原本的UIView之上,但是官方在文件裡並不推薦這麼做,我前一篇的官方文件翻譯中有寫

當在專案中替換使用AsyncDisplayKit的時候,一個經常犯的錯誤就是把一個Node節點直接新增到一個現有的view檢視層次結構裡。這樣做會導致你的節點在渲染的時候會閃爍一下

相反,你應該你應該把nodes節點,當做一個子節點新增到一個容器類裡。這些容器類負責告訴所包含的節點,他們現在都是什麼狀態,以便於儘可能有效的載入資料與渲染。你可以把這些類當做UIKit和ASDK的整合點

藉助nodes容器可以更好的對容器內子nodes進行管理和渲染控制,這是官方推薦使用的,因此我們引出了節點容器的概念

ASViewController

ASViewController就是這樣的一種節點容器,它並非繼承自ASDisplayNode,而是直接繼承自UIViewController,就好像每一個UIViewController一定要有一個self.view一樣,ASViewController必須由一個ASDisplayNode進行初始化。

ASTableNode

ASCollectionNode

這兩個節點,本身就是一個ASDisplayNode節點,但它同時也有節點容器的作用

不僅如此,Table和Collection都是用於滾動並且批量展示資料的,ASDK還特意為此封裝了一套複雜的處理----滾動情況下的資料非同步載入過程。

因此他內部有兩個很特殊的控制器

  • ASRangeController 用於智慧判斷滾動範圍和滾動方向,提起對即將滾入螢幕的區域進行預處理控制,包括預處理資料載入,和預處理渲染
  • ASDataController 專門用於資料相關的載入控制,在RangeController的指揮下,對指定區域內的資料進行載入。

AsyncDisplayKit的其他元件

講到這裡,還有2個重要的東西沒說明

  • ASLayout佈局功能:ASDK專門基於CSS Flex Box佈局方案,重寫了一套自己的佈局演算法,沒有依賴於UIKit的佈局,就是為了能讓這套演算法在非同步執行緒裡也能運算頁面佈局,ASDisplayNode,可以直接對他設定約束,也可以直接設定frame,postion,並且有專門的measure方法可以執行緒安全的去計算自己,以及所有子節點的佈局位置。
  • ASAsyncTransaction非同步控制:ASDK專為非同步渲染而寫的一套非同步佇列控制,每當ASDisplayNode內部的ASDisplayLayer發生display方法的時候,就是主執行緒將要發生繪製的時候,會把相關繪製的操作,ASDisplayNode會將繪製任務提交給ASAsyncTransaction,在他內部的執行緒佇列裡進行繪製運算,當運算完畢,將繪製結果拋回主執行緒渲染到螢幕上。

OverView

流程

大致的輪廓可以看上面,ASDK非常大,裡面還有太多太多的細節,比如專門為ASText相關的Node,寫了一整套獨特的ASTextLayout,整個框架裡很多關鍵的類都可以深入展開,詳細說太多太多

AsyncDisplay(等待下篇)

下一篇分析就決定從ASDisplayNode + ASAsyncTransaction入手,重點去拆解學習,非同步渲染這個過程。聚焦於整個Display環節。

我的本意是重點學習和分析非同步渲染,然後可以不引入ASDK如此大的framework來解決實際專案中遇到的渲染效能問題。

至於ASLayout以及RangeController,DataController,由於ASDK太大,短時間內由於涵蓋的東西太多,慢慢來吧╮(╯_╰)╭

相關文章

相關文章