前言:
app性能的優化一直是一個須要認真對待的問題,特別是項目越複雜這個須要優化的點就更加劇要,談到性能優化就繞不開圖片圖形的處理。git
代碼實踐部分請移步:github
1、圖片從磁盤中讀入到顯示到屏幕全過程
一、圖片的加載過程:
- 使用 +imageWithContentsOfFile: 方法從磁盤中加載一張圖片或 -[UIImage imageNamed:@"xx.JPG"]此時圖片並無解碼;
- 初始化完成的UITmage 賦值給 UIImageView;
-
接着一個隱式的 CATransaction 捕獲到了 UIImageView 圖層樹的變化;面試
-
在主線程的下一個 runloop 到來時,Core Animation 提交了這個隱式的 transaction ,這個過程可能會對圖片進行 copy 操做,而受圖片是否字節對齊等因素的影響,這個 copy 操做可能會涉及如下部分或所有步驟:編程
- 分配內存緩衝區用於管理文件 IO 和解壓縮操做;
- 將文件數據從磁盤讀到內存中;
- 將壓縮的圖片數據解碼成未壓縮的位圖形式,這是一個很是耗時的 CPU 操做;
- 最後 Core Animation 中CALayer使用未壓縮的位圖數據渲染 UIImageView 的圖層。
- CPU計算好圖片的Frame,對圖片解壓以後.就會交給GPU來作圖片渲染。
由上面的步驟可知,圖片的解壓縮是一個很是耗時的 CPU 操做,而且它默認是在主線程中執行的。那麼當須要加載的圖片比較多時,就會對咱們應用的響應性形成嚴重的影響,尤爲是在快速滑動的列表上,這個問題會表現得更加突出。性能優化
二、渲染圖片到屏幕上
- iOS設備給用戶視覺反饋其實都是經過QuartzCore框架來進行的,說白了,全部用戶最終看到的顯示界面都是圖層合成的結果,而圖層便是QuartzCore中的CALayer。
- 一般咱們開發中使用的視圖即UIView,他並非直接顯示在屏幕上的,你能夠把他想象成一個裝有顯示層CALayer的容器。咱們在在建立視圖對象的時候,系統會自動爲該視圖建立一個CALayer;固然咱們也能夠本身再往該視圖中加入新的CALayer層。等到須要顯示的時候,系統硬件將把全部層進行拷貝,而後按Z軸的高低合成最終的合成效果。
三、圖片渲染大體流程
- 在 VSync 信號到來後,主線程開始在cpu上作計算。
- CPU計算顯示內容:視圖建立、佈局計算、圖片解碼、文本繪製等。
- GPU進行渲染:CPU將計算好的內容提交給GPU,GPU 進行變換、合成、渲染。
- GPU 會把渲染結果提交到幀緩衝區去,等待下一次 VSync 信號到來時顯示到屏幕上。
關於渲染更多知識點,例如離屏渲染等由於篇幅太長不利於學習,這部分放在後面app性能篇繼續學習。bash
2、圖形處理相關框架
經過以上圖片加載顯示的理論學習,咱們就須要來繼續學習一下圖形處理的相關理論,畢竟在開發過程當中咱們沒法,性能上也不容許,全部圖片的顯示都用UIimage從磁盤或內存中讀入。同時一些界面顯示也或多或少要使用到圖形處理框架。 網絡
一、iOS與圖形圖像處理相關的框架彙總:
- 界面圖形框架 -- UIKit
- 核心動畫框架 -- Core Animation
- 蘋果封裝的圖形框架 -- Core Graphics & Quartz 2D
- 傳統跨平臺圖形框架 -- OpenGL ES
- 蘋果最新力推的圖形框架 -- Metal
- 適合圖片的蘋果濾鏡框架 -- Core Image
適合視頻的第三方濾鏡方案 -- GPUImage (第三方不屬於系統,這裏列出來學習)
- 遊戲引擎 -- Scene Kit (3D) 和 Sprite Kit (2D)
- 計算機視覺在iOS的應用 -- OpenCV for iOS
毫無疑問,開發者們接觸得最多的框架是如下幾個,UIKit、Core Animation,Core Graphic, Core Image。下面簡要介紹這幾個框架,順便介紹下GPUImage
:app
二、界面圖形框架 -- UIKit(穿插使用其餘圖形處理框架)
- UIKit是一組Objective-C API,爲線條圖形、Quartz圖像和顏色操做提供Objective-C 封裝,並提供2D繪製、圖像處理及用戶接口級別的動畫。
- UIKit包括UIBezierPath(繪製線、角度、橢圓及其它圖形)、UIImage(顯示圖像)、UIColor(顏色操做)、UIFont和UIScreen(提供字體和屏幕信息)等類以及在位圖圖形環境、PDF圖形環境上進行繪製和 操做的功能等, 也提供對標準視圖的支持,也提供對打印功能的支持。
- UIKit與Core Graphics的關係:
在UIKit中,UIView類自己在繪製時自動建立一個圖形環境,即Core Graphics層的CGContext類型,做爲當前的圖形繪製環境。在繪製時能夠調用 UIGraphicsGetCurrentContext 函數得到當前的圖形環境;框架
例如:
//這段代碼就是在UIView的子類中調用 UIGraphicsGetCurrentContext 函數得到當前的圖形環境,而後向該圖形環境添加路徑,最後繪製。
- (void)drawRect:(CGRect)rect {
//1.獲取上下文
CGContextRef contextRef = UIGraphicsGetCurrentContext();
//2.描述路徑
UIBezierPath * path = [UIBezierPath bezierPath];
//起點
[path moveToPoint:CGPointMake(10, 10)];
//終點
[path addLineToPoint:CGPointMake(100, 100)];
//設置顏色
[[UIColor whiteColor]setStroke];
//3.添加路徑
CGContextAddPath(contextRef, path.CGPath);
//顯示路徑
CGContextStrokePath(contextRef);
}
複製代碼
三、核心動畫框架 -- Core Animation
- Core Animation 是經常使用的框架之一。它比 UIKit 和 AppKit 更底層。正如咱們所知,UIView底下封裝了一層CALayer樹,Core Animation 層是真正的渲染層,咱們之因此能在屏幕上看到內容,真正的渲染工做是在 Core Animation 層進行的。
- Core Animation 是一套Objective-C API,實現了一個高性能的複合引擎,並提供一個簡單易用的編程接口,給用戶UI添加平滑運動和動態反饋能力。
- Core Animation 是 UIKit 實現動畫和變換的基礎,也負責視圖的複合功能。使用Core Animation能夠實現定製動畫和細粒度的動畫控制,建立複雜的、支持動畫和變換的layered 2D視圖
- OpenGL ES的內容也能夠與Core Animation內容進行集成。
- 爲了使用Core Animation實現動畫,能夠修改 層的屬性值 來觸發一個action對象的執行,不一樣的action對象實現不一樣的動畫。Core Animation 提供了一組基類及子類,提供對不一樣動畫類型的支持:
- CAAnimation 是一個抽象公共基類,CAAnimation採用CAMediaTiming 和CAAction協議爲動畫提供時間(如週期、速度、重複次數等)和action行爲(啓動、中止等)。
- CAPropertyAnimation 是 CAAnimation的抽象子類,爲動畫提供一個由一個key路徑規定的層屬性的支持;
- CABasicAnimation 是CAPropertyAnimation的具體子類,爲一個層屬性提供簡單插入能力。
- CAKeyframeAnimation 也是CAPropertyAnimation的具體子類,提供key幀動畫支持。
四、蘋果封裝的圖形框架 -- Core Graphics & Quartz 2D
- Core Graphics(使用Quartz 2D引擎)
- Core Graphics是一套C-based API, 支持向量圖形,線、形狀、圖案、路徑、剃度、位圖圖像和pdf 內容的繪製
- Core Graphics 也是經常使用的框架之一。它用於運行時繪製圖像。開發者們能夠經過 Core Graphics 繪製路徑、顏色。當開發者須要在運行時建立圖像時,可使用 Core Graphics 去繪製,運行時實時計算、繪製一系列圖像幀來實現動畫。與之相對的是運行前建立圖像(例如從磁盤中或內存中已經建立好的UIImage圖像)。
- Quartz 2D
- Quartz 2D是Core Graphics中的2D 繪製呈現引擎。Quartz是資源和設備無關的,提供路徑繪製,anti-aliased呈現,剃度填充圖案,圖像,透明繪製和透明層、遮蔽和陰影、顏色管理,座標轉換,字體、offscreen呈現、pdf文檔建立、顯示和分析等功能。
- Quartz 2D可以與全部的圖形和動畫技術(如Core Animation, OpenGL ES, 和 UIKit 等)一塊兒使用。Quartz 2D採用paint模式進行繪製。
- Quartz 2D提供的主要類包括:
- CGContext:表示一個圖形環境;
- CGPath:使用向量圖形來建立路徑,並可以填充和stroke;
- CGImage:用來表示位圖;
- CGLayer:用來表示一個可以用於重複繪製和offscreen繪製的繪製層;
- CGPattern:用來表示Pattern,用於重複繪製;
- CGShading和 CGGradient:用於繪製剃度;
- CGColor 和 CGColorSpace;用來進行顏色和顏色空間管理;
- CGFont, 用於繪製文本;
- CGPDFContentStream、CGPDFScanner、CGPDFPage、CGPDFObject,CGPDFStream, CGPDFString等用來進行pdf文件的建立、解析和顯示。
五、適合圖片的蘋果濾鏡框架 -- Core Image
-
Core Image 與 Core Graphics 偏偏相反,Core Graphics 用於在運行時建立圖像,而 Core Image 是用來處理已經建立的圖像的。Core Image 框架擁有一系列現成的圖像過濾器,能對已存在的圖像進行高效的處理。函數
-
Core Image 是 iOS5 新加入到 iOS 平臺的一個圖像處理框架,提供了強大高效的圖像處理功能, 用來對基於像素的圖像進行操做與分析, 內置了不少強大的濾鏡(Filter) (目前數量超過了180種), 這些Filter 提供了各類各樣的效果, 而且還能夠經過 濾鏡鏈 將各類效果的 Filter疊加 起來造成強大的自定義效果。
- 一個 濾鏡 是一個對象,有不少輸入和輸出,並執行一些變換。例如,模糊濾鏡可能須要輸入圖像和一個模糊半徑來產生適當的模糊後的輸出圖像。
- 一個 濾鏡鏈 是一個連接在一塊兒的濾鏡網絡,使得一個濾鏡的輸出能夠是另外一個濾鏡的輸入。以這種方式,能夠實現精心製做的效果。
- iOS8 以後更是支持自定義 CIFilter,能夠定製知足業務需求的複雜效果。
-
Core Image 的優勢在於十分高效。大部分狀況下,它會在 GPU 中完成工做,但若是 GPU 忙,會使用 CPU 進行處理。若是設備支持 Metal,那麼會使用 Metal 處理。這些操做會在底層完成,Apple 的工程師們已經幫助開發者們完成這些操做了。
- 例如他能夠根據需求選擇 CPU 或者 GPU 來處理。
// 建立基於 CPU 的 CIContext 對象 (默認是基於 GPU,CPU 須要額外設置參數)
context = [CIContext contextWithOptions: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]];
// 建立基於 GPU 的 CIContext 對象
context = [CIContext contextWithOptions: nil];
// 建立基於 GPU 的 CIContext 對象
EAGLContext *eaglctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
context = [CIContext contextWithEAGLContext:eaglctx];
複製代碼
-
Core Image 的 API 主要就是三類:
- CIImage 保存圖像數據的類,能夠經過UIImage,圖像文件或者像素數據來建立,包括未處理的像素數據。
- CIFilter 表示應用的濾鏡,這個框架中對圖片屬性進行細節處理的類。它對全部的像素進行操做,用一些鍵-值設置來決定具體操做的程度。
- CIContext 表示上下文,如 Core Graphics 以及 Core Data 中的上下文用於處理繪製渲染以及處理託管對象同樣,Core Image 的上下文也是實現對圖像處理的具體對象。能夠從其中取得圖片的信息。
六、適合視頻的第三方濾鏡方案 -- GPUImage
- GPUImage是一個基於OpenGL ES 2.0的開源的圖像處理庫,優點:
- 最低支持 iOS 4.0,iOS 5.0 以後就支持自定義濾鏡。在低端機型上,GPUImage 有更好的表現。
- GPUImage 在視頻處理上有更好的表現。
- GPUImage 的代碼已經開源。能夠根據本身的業務需求,定製更加複雜的管線操做。可定製程度高。
參考文章: