UIView繪制流程圖
下面我們來(lái)對(duì)這個(gè)流程進(jìn)行說(shuō)明:
當(dāng)我們調(diào)用[UIView setNeedsDisplay]方法時(shí),并沒(méi)有執(zhí)行立即執(zhí)行繪制工作胯究。
而是馬上調(diào)用[view.layer setNeedsDisplay]方法,給當(dāng)前l(fā)ayer打上臟標(biāo)記纸巷。
在當(dāng)前RunLoop快要結(jié)束的時(shí)候調(diào)用layer 的display方法裙戏,來(lái)進(jìn)入到當(dāng)前視圖的真正繪制當(dāng)中凸主。
在layer的display方法內(nèi)部缴川,系統(tǒng)會(huì)判斷l(xiāng)ayer的layer.delegate是否實(shí)現(xiàn)了displayLayer:方法茉稠,a.如果沒(méi)有實(shí)現(xiàn),則執(zhí)行系統(tǒng)的繪制流程;b.如果實(shí)現(xiàn)了則會(huì)進(jìn)入異步繪制的入口把夸。
最后把繪制完的backing store(可以理解為位圖)提交給GPU而线。
首先CALayer內(nèi)部會(huì)創(chuàng)建一個(gè)CGContextRef,在drawRect方法中,可以通過(guò)上下文堆棧當(dāng)中的取出這個(gè)context,拿到的就是當(dāng)前控件或者說(shuō)視圖的上下文或者說(shuō)是backing store
然后layer會(huì)判斷它是否有代理,若沒(méi)有,則調(diào)用CALayer的drawInContext吞获。
若有則調(diào)用代理方法,然后做當(dāng)前視圖的繪制工作(這一步發(fā)生在系統(tǒng)內(nèi)部當(dāng)中),再在合適的時(shí)機(jī),基于drawRect回調(diào)方法,
drawRect默認(rèn)操作是什么都不做,而之所以有這個(gè)接口,就是為了讓我們?cè)谙到y(tǒng)繪制之上,可以做些自定義的繪制工作况凉。
最后再由CALayer上傳對(duì)應(yīng)的backing store給GPU,這里的backing store我們可以理解為位圖谚鄙。
異步繪制流程
-[layer.delegate displayLayer:]
基于layer的delegate,如果實(shí)現(xiàn)了displayLayer方法,就可以進(jìn)入到異步繪制流程當(dāng)中
在異步繪制過(guò)程中, 需要代理去負(fù)責(zé)生成對(duì)應(yīng)的bitmap
設(shè)置該bitmap作為layer.contents屬性的值
異步繪制的機(jī)制和流程
左側(cè)是主隊(duì)列各拷,右側(cè)是全局并發(fā)隊(duì)列
假如在某一時(shí)機(jī)調(diào)用了setNeedsDiaplay方法后
在當(dāng)前runloop將要結(jié)束的時(shí)候,會(huì)有系統(tǒng)調(diào)用視圖所對(duì)應(yīng)layer的display方法
如果代理實(shí)現(xiàn)了displayLayer方法,會(huì)調(diào)用這個(gè)代理的displayLayer這個(gè)方法
然后通過(guò)子線程的切換,我們會(huì)在子線程中去做位圖的繪制,此時(shí)主線程可以去做些其他的工作
然后再回到主隊(duì)列中,提交這個(gè)位圖,設(shè)置給CALayer的contents屬性
子線程的繪制
通過(guò)CGBitmapContextCreat方法,來(lái)創(chuàng)建一個(gè)位圖的上下文
通過(guò)CoreGraphic的相關(guān)API,可以做當(dāng)前UI控件的一些繪制工作
之后通過(guò)CGBitmapContextCreatImage方法,根據(jù)所繪制的上下文,生成一張CGImage圖片