UIKit 效能除錯

2021-07-13 03:44:28 字數 4396 閱讀 7595

1.思考一下下面的問題 1.

為什麼要把控制項盡量設定

成不透明的,如果是透明的會有什麼影響,如何檢測這種影響?2.

為什麼cell

中的,盡可能要使用正確的大小、格式,如果錯誤會有什麼影響,如何檢測這種影響?3.

為什麼設定陰影和圓

角有可能影響滑動時流暢度?4.

shouldrasterize

和離屏渲染的關係是什麼,何時應該使用

?1.圖層混合

首先我們要明白畫素的概念,螢幕上每乙個點都是乙個畫素,畫素有r、

g、b三種顏色構成

(有時候還帶有

alpha值)

。如果某一塊區域上覆蓋了多個

layer,

最後的顯示效果受到這些

layer

的共同影響。舉個例子,上層是藍色

(rgb=0,0,1),

透明度為

50%,下層是紅色

(rgb=1,0,0)

。那麼最終的顯示效果是紫色

(rgb=0.5,0,0.5)

。這種顏色的混合

(blending)

需要消耗一定的

gpu資源,因為實際上可能不止只有兩層。如果只想顯示最上層的藍色,可以把它的透明度設定為

100%

,這樣gpu

會忽略下面所有的

layer

,從而節約了很多不必要的運算。

第乙個除錯選項

"colorblended layers"

正是用於檢測**發生了圖層混合,並用紅色標記出來。因此我們需要盡可能減少看到的紅色區域。一旦發現應該想法設法消除它。開始除錯後勾選這個選項,我們在手機上可以看到如下的場景:

1171077-6fb5ba7033c1f825.png

很多文章裡說把控制項設定為opaque = true,其原理就是希望避免圖層混合,然而這種調優一般情況下用處不大。因為uiviewopaque屬性預設值就是true,也就是說只要不是人為設定成透明,都不會出現圖層混合。比如demo中就沒有任何透明的控制項。

opaque屬性更重要的是backgroundcolor屬性,如果不設定這個屬性,控制項依然被認為是透明的,所以我們做的第乙個優化是在customtablecell類的init方法中新增一行**:

label.backgroundcolor = uicolor

.whitecolor()

雖然在白色背景下,這行**無法肉眼看到效果,但重新除錯後我們可以發現label的紅色消失了。也正是因為對背景顏色的不重視,它成了影響滑動效能的第乙個殺手。

如果label

文字有中文,依然會出現圖層混合

,這是因為

當uilabel

的文字是中文的時候,其實它裡面包含了乙個子檢視,圖上的白色背景就是那個子檢視。一般情況下,我們的

中都是顯示中文的,那麼如何去避免圖層混合呢

正當我不知道如何是好的時候,在stackoverflow上搜到了這個問題的答案。

鏈結在這裡

一是設定

layer

的**,然後實現

-drawlayer:incontext

方法,二是新建

catextlayer

子類,重寫

-drawincontext:方法

。 第四個選項的使用場景不多,我們直接看一下第五個選項「color misaligned images」。它表示如果需要縮放則標記為黃色,如果沒有畫素對齊則標記為紫色。勾選上這個選項並進行除錯,可以看到如下場景:

每個uiimageview的大小都是180x180,而只有第二張的畫素大小是360x360。因此除了第二張,其他的都需要被縮放。的縮放需要占用時間,因此我們要盡可能保證無論是本地還是從網路或取得的大小,都與其frame保持一致。

調整所有的畫素大小以避免不必要的縮放。

畫素在記憶體中的布局和它在磁碟中的儲存方式並不相同。考慮一種簡單的情況:每個畫素有r、g、b和alpha四個值,每個值占用1位元組,因此每個畫素占用4位元組的記憶體空間。一張1920*1080的**(iphone6 plus的解析度)一共有2,073,600個畫素,因此占用了超過8mb的記憶體。但是一張同樣解析度的png格式或jpeg格式的一般情況下不會有這麼大。這是因為jpeg將畫素資料進行了一種非常複雜且可逆的轉化。

當我們開啟jpeg格式的時,cpu會進行一系列運算,將jpeg解壓成畫素資料。顯然這個工作會消耗不少時間,所以不應該在滑動時進行,我們應該預先處理好。

commit transaction和decode在同一幀內進行,如果這兩個操作的耗時超過16.67s,draw calls就會延遲到下一幀,從而導致fps值的降低。下面是commit transaction的詳細流程:

在第三步的prepare中,cpu主要處理兩件事:

把從png或jpeg等格式中解壓出來,得到畫素資料

如果gpu不支援這種顏色各式,cpu需要進行格式轉換

離屏渲染表示渲染發生在螢幕之外,你可能認為這是一句廢話。為了真正解釋清楚什麼是離屏渲染,我們先來看一下正常的渲染通道(render-pass):

首先,opengl提交乙個命令到command buffer,隨後gpu開始渲染,渲染結果放到render buffer中,這是正常的渲染流程。但是有一些複雜的效果無法直接渲染出結果,它需要分步渲染最後再組合起來,比如新增乙個蒙版(mask):

在前兩個渲染通道中,gpu分別得到了紋理(texture,也就是那個相機圖示)和layer(藍色的蒙版)的渲染結果。但這兩個渲染結果沒有直接放入render buffer中,也就表示這是離屏渲染。直到第三個渲染通道,才把兩者組合起來放入render buffer中。離屏渲染意味著把渲染結果臨時儲存,等用到時再取出,因此相對於普通渲染更占用資源。

第六個選項「color offscreen-rendered yellow」會把需要離屏渲染的地方標記為黃色,大部分情況下我們需要盡可能避免黃色的出現。離屏渲染可能會自動觸發,也可以手動觸發。以下情況可能會導致觸發離屏渲染:

重寫drawrect方法

有mask或者是陰影(layer.maskstobounds, layer.shadow*),模糊效果也是一種mask

layer.shouldrasterize = true

前兩者會自動觸發離屏渲染,第三種方法是手動開啟離屏渲染。

開始除錯並勾選「color offscreen-rendered yellow」,

如果沒有進行第二步優化,你會發現label也是黃色。可以看到tabbar和statusbar也是黃色,這是因為它們使用了模糊效果。也是黃色,這說明它也進行了離屏渲染,觀察原始碼後發現主要原因是它使用了陰影,接下來我們進行第四個優化,在設定陰影效果的四行**下面新增一行:

imgview.layer.shadowpath = uibezierpath(rect: imgview.bounds).cgpath
這行**制定了陰影路徑,如果沒有手動指定,core animation會去自動計算,這就會觸發離屏渲染。如果人為指定了陰影路徑,就可以免去計算,從而避免產生離屏渲染。

設定cornerradius本身並不會導致離屏渲染,但很多時候它還需要配合layer.maskstobounds = true使用。根據之前的總結,設定maskstobounds會導致離屏渲染。解決方案是盡可能在滑動時避免設定圓角,如果必須設定圓角,可以使用光柵化技術將圓角快取起來:

// 設定圓角

label.layer.maskstobounds = true

label.layer.cornerradius = 8

label.layer.shouldrasterize = true

label.layer.rasterizationscale = layer.contentsscale

確保控制項的opaque屬性設定為true,確保backgroundcolor和父檢視顏色一致且不透明

如無特殊需要,不要設定低於1的alpha

確保uiimage沒有alpha通道

確保大小和frame一致,不要在滑動時縮放

確保顏色格式被gpu支援,避免勞煩cpu轉換

絕大多數時候離屏渲染會影響效能

重寫drawrect方法,設定圓角、陰影、模糊效果,光柵化都會導致離屏渲染

設定陰影效果是加上陰影路徑

滑動時若需要圓角效果,開啟光柵化

golang除錯效能分析

golang程式的cpu及記憶體使用情況效能分析 1.runtime.memstats檢視記憶體占用情況 讀取當前記憶體資訊的方法 func printmemstats func test log.println loop end.func main 主線程 睡眠等待 alloc golang語言框...

UIKit學習 02 關於UIButton

按鈕的三種狀態 要為按鈕設定三種狀態都不同的外觀,那麼按鈕的type要設定為custom uibutton的常見設定 setget 建立 建立按鈕 uibutton btn uibutton alloc init 設定背景 btn setbackgroundimage uiimage imagena...

mysql效能除錯,不斷總結!

mysql在遇到嚴重效能問題時,一般都有這麼幾種可能 1 索引沒有建好 2 sql寫法過於複雜 3 配置錯誤 4 機器實在負荷不了 1.索引沒建好,乙個辦法,後台執行指令碼,show processlist 實時檢視mysql的工作情況,記錄,鎖死mysql的語句。然後,desc explain 語...