面試-iOS圖片渲染

渲染圖片到屏幕上

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

軟件對圖形處理的流程

對于這塊詳細(xì)的介紹請看:繪制像素到屏幕上

GPU在相識像素方面起核心作用(在浮點運算方面做的很好)。它連接到CPU,在兩者間有OpenGL,Core Animation 和 Core Graphics來做數(shù)據(jù)傳輸。上圖的流程確保了圖形的繪制。其次,在透明和不透明方面,當(dāng)源紋理是完全不透明的情況下R = S + D * ( 1 – ?alpha )這個繪制公式,就不需要合成像素值,大大提高了性能通過CALayer的opaque來設(shè)置。ps:Quartz是iPhone OS的窗口服務(wù)器和描畫技術(shù)的一般叫法。Core Graphics框架是Quartz的核心,也是內(nèi)容描畫的基本接口。Core Graphics就是調(diào)用drawRect()方法繪制上下文時候的一系列函數(shù)

離屏渲染

這個知識點需要知道當(dāng)前屏幕渲染的概念,當(dāng)前屏幕渲染是指GPU在的渲染操作是在當(dāng)前的屏幕緩沖區(qū)中進(jìn)行渲染的。
離屏渲染相比當(dāng)前屏幕渲染,所有不在當(dāng)前屏幕緩沖區(qū)進(jìn)行渲染的過程都是離屏渲染,即GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進(jìn)行渲染操作。這其中有一種特殊的渲染方式就是CPU渲染。這種情況發(fā)生在當(dāng)我們對UIView的DrawRect方法進(jìn)行重寫的情況下并在代碼中用到了Core Graphics技術(shù)進(jìn)行了操作,這就是CPU渲染。整個CPU在App內(nèi)同步完成,渲染得到的bitmap最后在提交給GPU進(jìn)行顯示。但是由于所有的Core Graphics都是線程安全的所以可以異步完成CPU渲染。

性能

1.由于離屏渲染需要多次的上下文切換:先從當(dāng)前屏幕切換到離屏進(jìn)行渲染操作;渲染結(jié)束后,切換回當(dāng)前屏幕將渲染完成之后的結(jié)果放到屏幕上。上下文切換的代價相當(dāng)大?。?!
2.離屏渲染需要新建一個緩沖區(qū)!

設(shè)置了下面的CALayer屬性都會觸發(fā)離屏繪制:
shouldRasterize(光柵化)
masks(遮罩)
shadows(陰影)
edge antialiasing(抗鋸齒)
group opacity(不透明)

看到了這個masks很容易就讓我想到了我們經(jīng)常用的設(shè)置圓角的makeToMasks屬性。嘿嘿,性能低下吧,那接下來就來高效的設(shè)置一個圓角圖形。

高效設(shè)置圓角圖形

在UIImage中添加一個類別


-(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;
}

針對于這種方法就是一定要注意這個圖片的背景色不能隨意設(shè)置因為在這種方法中我們刻意的避免的masks的使用,就是避免了離屏渲染,所以如果有背景色還是會影響視覺效果!core animation也不會變黃哦!

FPS

查看自己應(yīng)用程序是否卡頓--FPS
1.自帶工具Profile的Core Animation。查看FPS
2.通過CADisplayLink

聲明:frameInterval的固定值為1,表示是一秒鐘刷新60幀。duration是一幀維持的時間。CADisplayLink相比NSTimer的區(qū)別是,前者調(diào)用方法時間一定,而且相當(dāng)精準(zhǔn)。后者調(diào)用會受到runtime的繁忙程度影響。

CADisplayLink

首先它是一個定時器,需要我們手動加入到runloop。本質(zhì)上和NSTimer是一樣的。但是他不同的是每次頻率刷新的時候會調(diào)用方法。the selector on the target is called when the screen’s contents need to be updated.調(diào)用方法target中可以使用timestamp(時間戳)來計算FPS??梢酝ㄟ^時間戳的插值這樣計算1/(timestamp1-timestamp2)計算但是由于timestamp1-timestamp2差值很小不易計算一般通過count多計算幾次這樣計算count/(timestamp1-timestamp(n))--相當(dāng)精準(zhǔn)。
可以參考一個很好的源碼:Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 繪制像素到屏幕上 answer-huang22 Mar 2014 分享文章 一個像素是如何繪制到屏幕上去的?有很多...
    阿貍旅途T恤閱讀 1,779評論 0 7
  • 卷首語 歡迎來到 objc.io 的第三期! 這一期都是關(guān)于視圖層的。當(dāng)然視圖層有很多方面,我們需要把它們縮小到幾...
    評評分分閱讀 1,943評論 0 18
  • 圓角是一種很常見的視圖效果,相比于直角,它更加柔和優(yōu)美,易于接受。設(shè)置圓角會帶來一定的性能損耗,如何提高性能是一個...
    Chars閱讀 642評論 0 8
  • 在本系列上一篇《iOS 2D Graphic(1)—— Concept 基本概念和原理》中,我們已經(jīng)了解了關(guān)于iO...
    ac3閱讀 2,394評論 2 11
  • 李朝鳳像往常一樣在信紙上寫上“敬候坤祺”四個字落款。翻來覆去地把信看了幾遍,確定沒有寫上比較敏感會被截留的內(nèi)容后,...
    瀟湘楚裔閱讀 363評論 0 0

友情鏈接更多精彩內(nèi)容