渲染圖片到屏幕上
每一個(gè)像素點(diǎn)均由三個(gè)顏色組件構(gòu)成:紅,藍(lán),綠外加一個(gè)透明度。在每個(gè)蘋果產(chǎn)品上都有上百萬(wàn)個(gè)像素點(diǎn)需要繪制,并且需要一個(gè)穩(wěn)定的FPS支撐頁(yè)面的流暢度,這是一個(gè)很龐大的工作量。這是怎樣一個(gè)流程?
iOS設(shè)備給用戶視覺(jué)反饋其實(shí)都是通過(guò)QuartzCore框架來(lái)進(jìn)行的,說(shuō)白了,所有用戶最終看到的顯示界面都是圖層合成的結(jié)果,而圖層即是QuartzCore中的CALayer。
通常我們所說(shuō)的視圖即UIView,并不是直接顯示在屏幕上,而是在創(chuàng)建視圖對(duì)象的時(shí)候視圖對(duì)象會(huì)自動(dòng)創(chuàng)建一個(gè)層,而視圖對(duì)象把要顯示的東西繪制在層上,待到需要顯示時(shí)硬件將所有的層拷貝,然后按Z軸的高低合成最終的合成效果。

對(duì)于這塊詳細(xì)的介紹請(qǐng)看:繪制像素到屏幕上
GPU在相識(shí)像素方面起核心作用(在浮點(diǎn)運(yùn)算方面做的很好)。它連接到CPU,在兩者間有OpenGL,Core Animation 和 Core Graphics來(lái)做數(shù)據(jù)傳輸。上圖的流程確保了圖形的繪制。其次,在透明和不透明方面,當(dāng)源紋理是完全不透明的情況下R = S + D * ( 1 – ?alpha )這個(gè)繪制公式,就不需要合成像素值,大大提高了性能通過(guò)CALayer的opaque來(lái)設(shè)置。ps:Quartz是iPhone OS的窗口服務(wù)器和描畫技術(shù)的一般叫法。Core Graphics框架是Quartz的核心,也是內(nèi)容描畫的基本接口。Core Graphics就是調(diào)用drawRect()方法繪制上下文時(shí)候的一系列函數(shù)
離屏渲染
這個(gè)知識(shí)點(diǎn)需要知道當(dāng)前屏幕渲染的概念,當(dāng)前屏幕渲染是指GPU在的渲染操作是在當(dāng)前的屏幕緩沖區(qū)中進(jìn)行渲染的。
離屏渲染相比當(dāng)前屏幕渲染,所有不在當(dāng)前屏幕緩沖區(qū)進(jìn)行渲染的過(guò)程都是離屏渲染,即GPU在當(dāng)前屏幕緩沖區(qū)以外新開(kāi)辟一個(gè)緩沖區(qū)進(jìn)行渲染操作。這其中有一種特殊的渲染方式就是CPU渲染。這種情況發(fā)生在當(dāng)我們對(duì)UIView的DrawRect方法進(jìn)行重寫的情況下并在代碼中用到了Core Graphics技術(shù)進(jìn)行了操作,這就是CPU渲染。整個(gè)CPU在App內(nèi)同步完成,渲染得到的bitmap最后在提交給GPU進(jìn)行顯示。但是由于所有的Core Graphics都是線程安全的所以可以異步完成CPU渲染。
性能
1.由于離屏渲染需要多次的上下文切換:先從當(dāng)前屏幕切換到離屏進(jìn)行渲染操作;渲染結(jié)束后,切換回當(dāng)前屏幕將渲染完成之后的結(jié)果放到屏幕上。上下文切換的代價(jià)相當(dāng)大?。?!
2.離屏渲染需要新建一個(gè)緩沖區(qū)!
設(shè)置了下面的CALayer屬性都會(huì)觸發(fā)離屏繪制:
shouldRasterize(光柵化)
masks(遮罩)
shadows(陰影)
edge antialiasing(抗鋸齒)
group opacity(不透明)
看到了這個(gè)masks很容易就讓我想到了我們經(jīng)常用的設(shè)置圓角的makeToMasks屬性。嘿嘿,性能低下吧,那接下來(lái)就來(lái)高效的設(shè)置一個(gè)圓角圖形。
高效設(shè)置圓角圖形
在UIImage中添加一個(gè)類別
-(UIImage *)jg_drawRadius:(CGFloat)radius size:(CGSize) sizetoFit{
CGRect rect = CGRectMake(0, 0, sizetoFit.width, sizetoFit.height);//圖形大小
UIGraphicsBeginImageContextWithOptions(rect.size,false,[UIScreen mainScreen].scale);//繪制圖形按尺寸,透明,比例
CGContextAddPath(UIGraphicsGetCurrentContext(),[UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)].CGPath);//添加路徑
CGContextClip(UIGraphicsGetCurrentContext());//裁剪內(nèi)容
[self drawInRect:rect];
CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathFillStroke);
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return output;
}
針對(duì)于這種方法就是一定要注意這個(gè)圖片的背景色不能隨意設(shè)置因?yàn)樵谶@種方法中我們刻意的避免的masks的使用,就是避免了離屏渲染,所以如果有背景色還是會(huì)影響視覺(jué)效果!core animation也不會(huì)變黃哦!
FPS
查看自己應(yīng)用程序是否卡頓--FPS
1.自帶工具Profile的Core Animation。查看FPS
2.通過(guò)CADisplayLink
聲明:frameInterval的固定值為1,表示是一秒鐘刷新60幀。duration是一幀維持的時(shí)間。CADisplayLink相比NSTimer的區(qū)別是,前者調(diào)用方法時(shí)間一定,而且相當(dāng)精準(zhǔn)。后者調(diào)用會(huì)受到runtime的繁忙程度影響。
CADisplayLink
首先它是一個(gè)定時(shí)器,需要我們手動(dòng)加入到runloop。本質(zhì)上和NSTimer是一樣的。但是他不同的是每次頻率刷新的時(shí)候會(huì)調(diào)用方法。the selector on the target is called when the screen’s contents need to be updated.調(diào)用方法target中可以使用timestamp(時(shí)間戳)來(lái)計(jì)算FPS。可以通過(guò)時(shí)間戳的插值這樣計(jì)算1/(timestamp1-timestamp2)計(jì)算但是由于timestamp1-timestamp2差值很小不易計(jì)算一般通過(guò)count多計(jì)算幾次這樣計(jì)算count/(timestamp1-timestamp(n))--相當(dāng)精準(zhǔn)。
可以參考一個(gè)很好的源碼:Github