UIView的繪制原理
調(diào)用UIView的setNeedsDisplay方法時(shí),實(shí)際上并沒有進(jìn)行當(dāng)前視圖的繪制過程,而系統(tǒng)會(huì)立刻調(diào)用它所對(duì)應(yīng)的layer的setNeedsDisplay方法,這相當(dāng)于在layer上面打上了一個(gè)“臟標(biāo)記”。而后在當(dāng)前runLoop快要結(jié)束的時(shí)候,才會(huì)調(diào)用CALayer的display方法,然后就進(jìn)入到當(dāng)前視圖真正的繪制流程。對(duì)于CALayer的display方法,在它的內(nèi)部實(shí)現(xiàn)中會(huì)先判斷它的delegate是否會(huì)響應(yīng)displayLayer:這個(gè)方法:如果不響應(yīng)這個(gè)方法,那就進(jìn)入系統(tǒng)的繪制流程。如果響應(yīng)這個(gè)方法,那就進(jìn)入視圖的異步繪制流程。

系統(tǒng)繪制流程
在CALayer內(nèi)部會(huì)創(chuàng)建一個(gè)backing store(可以理解為CGContextRef,也就是通常我們所說的上下文,在drawRect方法當(dāng)中,可以通過上下文堆棧取出棧頂?shù)腸ontext,拿到的就是當(dāng)前視圖/控件的上下文),然后layer判斷它是否有代理:如果沒有,就會(huì)調(diào)用CALayer的drawInContext:方法。如果有,就會(huì)調(diào)用它的代理的drawLayer:inContext:方法。然后做當(dāng)前視圖的系統(tǒng)繪制工作,之后在合適的時(shí)機(jī)給予我們一個(gè)回調(diào)方法,也就是我們所熟悉的drawRect:方法(drawRect:方法默認(rèn)是什么都不做),讓我們?cè)谙到y(tǒng)繪制的基礎(chǔ)之上,做一些其它的相關(guān)繪制工作。然后,這兩個(gè)分支都是由CALayer來上傳backing store(可以理解為最終的位圖bitmap)到GPU中,最終結(jié)束系統(tǒng)繪制流程。

異步繪制原理
如果layer的delegate實(shí)現(xiàn)了displayLayer:這個(gè)方法,我們就可以進(jìn)入視圖的異步繪制流程中。這時(shí)候就是通過代理來生成對(duì)應(yīng)的bitmap。同時(shí)我們要設(shè)置該bitmap作為layer.contents屬性的值。

異步繪制流程
左側(cè)是主隊(duì)列,右側(cè)是全局隊(duì)列。如果我們調(diào)用了UIView的setNeedsDisplay方法,在當(dāng)前runLoop快要結(jié)束的時(shí)候,會(huì)由系統(tǒng)調(diào)用視圖所對(duì)應(yīng)的layer的diaplay方法,然后如果代理實(shí)現(xiàn)了displayLayer:方法,那么就會(huì)調(diào)用該方法。之后我們就可以通過線程的切換,在子線程(不局限于全局隊(duì)列)當(dāng)中進(jìn)行視圖的異步繪制【首先通過CGBitmapCoontextCreate()創(chuàng)建一個(gè)位圖上下文,然后通過CoreGraphic API進(jìn)行一些位圖的繪制工作,最后通過CGBitmapContextCreateImage()生成一張CGImage圖片】。最后回到主線程中,設(shè)置layer的contents屬性,完成視圖的異步繪制流程。
