天天看點

IOS使用Instrument-Time Profiler工具分析和優化性能問題

背景

前不久我做了一個富文本編輯工具,編輯器遇到了一個性能問題是添加多張圖檔,當滾動編輯區域,遇到圖檔切換的時候會有明顯的卡頓現象。這篇文章基于這個卡頓的性能問題進行性能瓶頸的分析以及做對應的優化。

可以打開這個連結 ios使用uitableview實作的富文本編輯器 檢視我的文章,這篇文章所用的項目也是基于這個項目的。

結果

最終的分析優化的結果把時間從90ms的數量級降低到了2ms的數量級,達到了一個比較流暢的效果。具體的分析優化步驟請往下看。

問題分析

既然問題是發生在圖檔切換的時候,圖檔是放在單獨的一個cell中的,那麼就嘗試在cell的渲染方法 cellforrowatindexpath 添加兩個log,檢視方法執行所用的時間。

IOS使用Instrument-Time Profiler工具分析和優化性能問題

對應的結果:

2017-08-11 06:12:48.744 richtexteditdemo[6867:1064632] ======begin render cell 

2017-08-11 06:12:48.749 richtexteditdemo[6867:1064632] ======end render cell 

2017-08-11 06:12:49.261 richtexteditdemo[6867:1064632] ======begin render cell 

2017-08-11 06:12:49.266 richtexteditdemo[6867:1064632] ======end render cell  

從日志列印的時間上看,大概每渲染一個cell隻要發幾毫秒的時間,貌似問題不會出現在這個位置,然而這并不是真相,很明顯的,其他地方不會影響到,是以得用更進階的分析工具去分析檢視。

發現問題

instrument是一個很好的性能分析工具,可以分析記憶體配置設定、記憶體洩漏、網絡情況、cpu占用等和性能有關的問題,目前的性能問題是耗時的問題,可以使用 instrument 的 time profiler 進行分析

讓這個清單滾動,并且有進行圖檔cell的切換

IOS使用Instrument-Time Profiler工具分析和優化性能問題

可以看到time profiler 有下面的記錄,紅色框中就是cell切換所耗費的時間值,這個時間的增長很明顯的高于其他值了,是以這個就是我們要定位到的地方了。

tips

alt + 滑鼠滾輪 -> 縮放時間軸

shift + 滑鼠滾輪 -> 移動時間軸

按住滑鼠框選 -> 選擇和定位時間軸

IOS使用Instrument-Time Profiler工具分析和優化性能問題

第一步要在時間軸上框選一個範圍,辨別選擇這個範圍進行分析,才能準确定位到這個問題,如圖(1)位置所示;第二步要選在堆棧中的某一個函數,一般的選擇到oc函數調用,更底層的函數調用就到了cf層是c語言實作的就不好分析了,是以這裡選擇的是 [uiimage drawinrect:blendmode:alpha] 這個函數分析,可以看到這個函數調用說花費的時間是 92ms,這是一個比較長的時間了,是以應該就是這裡導緻的卡頓了。

IOS使用Instrument-Time Profiler工具分析和優化性能問題

這個函數花費的時間和image圖檔的大小有關系的,選擇另一個時間峰值範圍,這個時間峰值範圍是發生在小圖之間的切換的

IOS使用Instrument-Time Profiler工具分析和優化性能問題

這個地方耗費的時間就比較小一點,不過也是達到了25ms,對于性能也是有一定的影響的。

解決問題

以上的分析可以得出結論:[uiimage drawinrect:blendmode:alpha] 函數的調用是會導緻性能問題的,因為uitextview内部處理圖檔的方式是通過調用 [uiimage drawinrect:blendmode:alpha] 函數繪制圖檔實作的。

IOS使用Instrument-Time Profiler工具分析和優化性能問題

既然是uitextview内部的處理方式,是以這個函數調用行為是應用層改變不了的,不過uiimage對象是我們可以控制的,或者可以改變圖檔的顯示方式來達到優化的目的,是以就有了以下的兩種方案。

方案1

第一種方案就是對預覽的圖檔進行壓縮,然後再設定到nstextattachmen中,放到uitextview中顯示

textattachment.image = self.image; 

// ===> 修改為 

// scaletosize用于壓縮原始的圖檔,textattachment中的image對象是壓縮過後的 

textattachment.image = [self.image scaletosize:showimagewidth];  

這樣修改之後大圖的滾到加載時間減少到了40ms左右

IOS使用Instrument-Time Profiler工具分析和優化性能問題

雖然減少了一半的時間,不過,40ms的時間還是比較長的,下面會繼續進行優化。

方案2

上面的方案進行了圖檔的壓縮,時間的耗費還是因為 [uiimage drawinrect:blendmode:alpha] 函數的調用,是以有沒有一種更好的方案呢?答案是肯定的,可以把傳給uitextview的image壓縮成一個很小的,(這一步也可以不必,傳遞一個空的uiimageview對象即可,這裡設定圖檔的主要原因是圖檔區域需要一個編輯的光标),然後在 uitextview 所對應的圖檔區域添加一個uiimageview,在uiimageview中設定原始的圖檔即可,這種方案會比方案1的效果好很多。

方案二幾個修改點:

1.設定nstextattachment的image為空的uiimage對象

//.... 

    nstextattachment *textattachment = [[nstextattachment alloc] init]; 

    cgrect rect = cgrectzero; 

    rect.size.width = showimagewidth; 

    rect.size.height = showimageheight; 

    textattachment.bounds = rect; 

    textattachment.image = [uiimage new]; 

    nsattributedstring *attachmentstring = [nsattributedstring attributedstringwithattachment:textattachment]; 

    //....  

2.cell添加imageview顯示image

[self.imagecontentview mas_remakeconstraints:^(masconstraintmaker *make) { 

    make.left.equalto(self).offset(_imagemodel.imageframe.origin.x); 

    make.top.equalto(self).offset(_imagemodel.imageframe.origin.y); 

    make.height.equalto(@(_imagemodel.imageframe.size.height)); 

    make.width.equalto(@(_imagemodel.imageframe.size.width)); 

}]; 

下面是使用方案2優化之後的分析圖

IOS使用Instrument-Time Profiler工具分析和優化性能問題

圖中可以看到 cellforrowatindexpath 方法總共占用了2ms的時間,從分析的堆棧中可以看到 uitextview setattributedtext: 方法才占用了1ms的時間,是以這個提升是很明顯的,因為傳遞了一個空的uiimageview對象,不用執行 [uiimage drawinrect:blendmode:alpha] 方法,使用了uiimageview直接設定image的方式幾乎不會占用時間,是以堆棧中看不到 [uiimageview setimage:] 方法調用的時間。

總結

instrument是一個很好工具,你用它可以很友善的幫我們定位到性能問題,問題找到了,那麼也就很容易找到解決方案了。

作者:aron1992

來源:51cto

繼續閱讀