性能優(yōu)化是軟件開(kāi)發(fā)中必備的一個(gè)技能,,而圖像又是其中影響性能最大的一個(gè)方面.早該記錄整理一下在iOS開(kāi)發(fā)中對(duì)圖像的優(yōu)化技巧了.
使用模擬器的測(cè)試工具可以查看當(dāng)前項(xiàng)目中圖片的性能情況.

-
Color Blended Layers
這個(gè)選項(xiàng)基于渲染程度對(duì)屏幕中的混合區(qū)域進(jìn)行綠到紅的高度(也就是多個(gè)半透明圖層的疊加) -
Color Misaligned images
會(huì)高亮那些被縮放或者拉伸以及沒(méi)有正確對(duì)齊到像素邊界的圖片(也就是非整型坐標(biāo))
這些中的大多數(shù)通常會(huì)導(dǎo)致圖片的不正常縮放,如把一張大圖當(dāng)作縮略圖顯示,或者不正確地模糊圖像 -
Color Copied Images
有時(shí)候 寄宿圖片(layer.content)的生成是由Core Animation被強(qiáng)制生成一些圖片,然后發(fā)送到渲染服務(wù)器,而不是簡(jiǎn)單的指向原始指針.
這個(gè)選項(xiàng)把這些圖片高亮為藍(lán)色
復(fù)制圖片對(duì)內(nèi)存和CPU來(lái)說(shuō)都是一項(xiàng)昂貴的操作,所以應(yīng)該盡可能的避免 -
Color Offscreen-Rendered(離屏渲染)
開(kāi)啟后會(huì)把離屏渲染的圖層高亮成黃色
` 以上性能優(yōu)化中, 有效的檢測(cè) 混合模式 和 拉伸圖像 在開(kāi)發(fā)中能夠提升圖像的性能
` 離屏渲染主要用于cell的性能優(yōu)化
直入主題.開(kāi)啟Color Misaligned images 圖片變黃需要拉伸的情況.
如圖:

這個(gè)列表中cell的圖片都是從網(wǎng)絡(luò)獲取,大小不定,都放在這個(gè)大小為100 * 100的ImageView里,圖片會(huì)因?yàn)槌叽绮灰欢M(jìn)行拉伸.所以為黃色...并且快速滑動(dòng)列表的時(shí)候FPS會(huì)降低到42左右.
解決辦法呢就是,在獲取到照片之后,利用(Core Graphics)繪制一張與將要填充的UIImageView尺寸相等的圖片,然后再賦值,尺寸相等后就免去了GPU拉伸消耗
注: Core Graphics的繪制過(guò)程是完全由CPU完成的,因此也叫軟件繪圖,雖然會(huì)消耗些CPU,但是之后這些圖片出現(xiàn)在屏幕上時(shí)不會(huì)再有拉伸操作了.
// 重繪過(guò)程
extension UIImage {
func compressImage(size: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let rect = CGRect(origin: CGPoint(), size: size)
draw(in: rect)
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
}
UIGraphicsBeginImageContextWithOptions(size, true, 0) //第二個(gè)參數(shù)是設(shè)置圖片是否是不透明的,,透明的話(huà)會(huì)有性能問(wèn)題
這個(gè)函數(shù)需要傳入一個(gè)圖片顯示時(shí)候的size..但是有時(shí)候圖片顯示的大小并不是一開(kāi)始就知道的.比如瀑布流中的圖片...這是這個(gè)優(yōu)化的局限性.
這個(gè)新繪制出來(lái)的UIImage不僅可以解決圖片拉伸的消耗問(wèn)題,還能降低內(nèi)存的占用,因?yàn)橐话闱闆r下圖片的大小是大于要顯示的尺寸大小的..如果是瀑布流中的圖片不方便確定最終大小,也可以不傳入尺寸,重繪一張圖片也會(huì)降低內(nèi)存的占用.

這里圖片的大小是固定的,在圖片下載來(lái)之后調(diào)用上述方法再賦值ImageView..再次運(yùn)行發(fā)現(xiàn)圖片沒(méi)有了黃色高亮...
但是快速滑動(dòng)之后FPS還是會(huì)降低到40左右..看來(lái)這項(xiàng)優(yōu)化對(duì)整體性能的影響還是很有限的.不過(guò)用Instruments監(jiān)測(cè)GPU的使用率發(fā)現(xiàn)比在優(yōu)化之前減少了不小.
此處FPS低還可能受Autolayout等影響.下一章再討論tableView的優(yōu)化.
開(kāi)啟Color Blended Layers 出現(xiàn)紅色高亮的情況 與高性能的切圓角
雖然使用核心繪圖進(jìn)行重繪也是一種消耗,<iOS核心動(dòng)畫(huà)高級(jí)技巧>中建議除非不得已不然不要進(jìn)行重繪,因?yàn)樗啾?Core Animation"使用CALayer效率低且差,不過(guò)它應(yīng)該是指各種動(dòng)畫(huà)效果.但是目前對(duì)于圖片的優(yōu)化來(lái)說(shuō),重繪確實(shí)可以做到對(duì)圖片的性能提高.
紅色高亮一般是因?yàn)閳D片是PNG并且有半透明的效果,像上面提到的,透明都了會(huì)增加性能的負(fù)擔(dān).
UIGraphicsBeginImageContextWithOptions(size, true, 0)
在重繪的時(shí)候第二個(gè)參數(shù)設(shè)置為true即可去掉透明效果.

但是原本透明的部分現(xiàn)在變成了難看的黑色,,與背景白色很違和,這不是我們想要的目的...總不能為了優(yōu)化,功能效果都變了..
因此我們需要加入一個(gè)參數(shù),把不違和的背景色填充到圖片中.
func circularImage(size: CGSize, backColor: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let rect = CGRect(origin: CGPoint(), size: size)
//填充背景色
backColor.setFill()
UIRectFill(rect)
draw(in: rect)
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
這樣,雖然圖片已經(jīng)被優(yōu)化為非透明的圖片,但是與透明圖片的效果無(wú)差.
高效的切圓角.加邊框
貝塞爾曲線(xiàn)自帶生成圓形的路徑path..而且還有切割當(dāng)前上下文的函數(shù)
func circularImage(size: CGSize, backColor: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let rect = CGRect(origin: CGPoint(), size: size)
//填充背景色
backColor.setFill()
UIRectFill(rect)
//切圓角
let path = UIBezierPath(ovalIn: rect)
path.addClip()
draw(in: rect)
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}
新加這兩行代碼便可完成切圓.
再加一個(gè)邊框的話(huà)同樣是利用這個(gè)path
func circularImage(size: CGSize, backColor: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let rect = CGRect(origin: CGPoint(), size: size)
//填充背景色
backColor.setFill()
UIRectFill(rect)
//切圓角
let path = UIBezierPath(ovalIn: rect)
path.addClip()
draw(in: rect)
//加圓框
path.lineWidth = 5
UIColor.orange.setStroke()
path.stroke()
let resultImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resultImage
}

至此,這兩種常見(jiàn)的需要優(yōu)化的圖片情況基本解決了.因?yàn)槭诌呏挥衖Phone6,,測(cè)試了幾個(gè)demo還未發(fā)現(xiàn)因?yàn)閳D片拉伸或透明導(dǎo)致的性能問(wèn)題...一個(gè)有130張需要拉伸的高清圖片demo,可能demo條件不足,滑動(dòng)起來(lái)FPS仍然60..有機(jī)會(huì)用一個(gè)4S測(cè)試一下..
CPU VS GPU
CPU(中央處理器), GPU(圖形處理器)..在iOS設(shè)備中,都有可以運(yùn)行不同軟件的可編程芯片,總的來(lái)說(shuō),CPU所做的工作在軟件層面,GPU在硬件層面.
使用CPU可以做任何事情,,但是對(duì)于圖像處理,GPU可以使用圖像對(duì)高度并行浮點(diǎn)運(yùn)算做了優(yōu)化,所以iOS設(shè)備把 屏幕圖像的渲染交給了GPU... CPU負(fù)責(zé)計(jì)算要顯示的內(nèi)容,,提交給GPU,去渲染.
動(dòng)畫(huà)和屏幕上的組合圖層實(shí)際上被一個(gè)單獨(dú)的進(jìn)程管理,而不是你的應(yīng)用程序,這個(gè)進(jìn)程就是所謂的 渲染服務(wù)
當(dāng)圖層進(jìn)行打包發(fā)送到渲染服務(wù)之后就不是我們能掌控的事情了..但是在渲染之前,我們可以進(jìn)行一切操作來(lái)決定哪些交給CPU,哪些給GPU,以及它們要做多少事情..