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

背景

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

能夠打開這個連接 iOS使用UITableView實現的富文本編輯器 查看個人文章,這篇文章所用的項目也是基於這個項目的。網絡

結果

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

問題分析

既然問題是發生在圖片切換的時候,圖片是放在單獨的一個Cell中的,那麼就嘗試在Cell的渲染方法 cellForRowAtIndexPath 添加兩個Log,查看方法執行所用的時間。
函數

輸入圖片說明
在這裏輸入圖片標題

對應的結果:

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的切換性能

圖片列表
圖片列表

能夠看到Time Profiler 有下面的記錄,紅色框中就是Cell切換所耗費的時間值,這個時間的增加很明顯的高於其餘值了,因此這個就是咱們要定位到的地方了。優化

Tipsui

  • alt + 鼠標滾輪 -> 縮放時間軸
  • shift + 鼠標滾輪 -> 移動時間軸
  • 按住鼠標框選 -> 選擇和定位時間軸

Time Profiler 截圖
Time Profiler 截圖

第一步要在時間軸上框選一個範圍,標識選擇這個範圍進行分析,才能準肯定位到這個問題,如圖(1)位置所示;第二步要選在堆棧中的某一個函數,通常的選擇到OC函數調用,更底層的函數調用就到了CF層是C語言實現的就很差分析了,因此這裏選擇的是 [UIImage drawInRect:blendMode:alpha] 這個函數分析,能夠看到這個函數調用說花費的時間是 92ms,這是一個比較長的時間了,因此應該就是這裏致使的卡頓了。spa

輸入圖片說明
在這裏輸入圖片標題

這個函數花費的時間和image圖片的大小有關係的,選擇另外一個時間峯值範圍,這個時間峯值範圍是發生在小圖之間的切換的.net

輸入圖片說明
在這裏輸入圖片標題

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

解決問題

以上的分析能夠得出結論:[UIImage drawInRect:blendMode:alpha] 函數的調用是會致使性能問題的,由於UITextView內部處理圖片的方式是經過調用 [UIImage drawInRect:blendMode:alpha] 函數繪製圖片實現的。

UITextView內部處理圖片
UITextView內部處理圖片

既然是UITextView內部的處理方式,因此這個函數調用行爲是應用層改變不了的,不過UIImage對象是咱們能夠控制的,或者能夠改變圖片的顯示方式來達到優化的目的,因此就有了如下的兩種方案。

方案1

第一種方案就是對預覽的圖片進行壓縮,而後再設置到NSTextAttachmen中,放到UITextView中顯示

textAttachment.image = self.image;
// ===> 修改成
// scaletoSize用於壓縮原始的圖片,textAttachment中的image對象是壓縮事後的
textAttachment.image = [self.image scaletoSize:showImageWidth];
複製代碼

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

方案1優化
方案1優化

雖然減小了一半的時間,不過,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];
        //....
複製代碼
  1. 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優化以後的分析圖

優化方案2
優化方案2

圖中能夠看到 cellForRowAtIndexPath 方法總共佔用了2ms的時間,從分析的堆棧中能夠看到 UITextView setAttributedText: 方法才佔用了1ms的時間,因此這個提高是很明顯的,由於傳遞了一個空的UIImageView對象,不用執行 [UIImage drawInRect:blendMode:alpha] 方法,使用了UIImageView直接設置Image的方式幾乎不會佔用時間,因此堆棧中看不到 [UIImageView setImage:] 方法調用的時間。

總結

Instrument是一個很好工具,你用它能夠很方便的幫咱們定位到性能問題,問題找到了,那麼也就很容易找到解決方案了。

相關文章
相關標籤/搜索