iOS性能優(yōu)化

性能優(yōu)化

所謂的性能優(yōu)化一般都是在運(yùn)行和內(nèi)存之間切換,平衡兩者的負(fù)荷。具體的性能到底好不好,一定要通過實(shí)際測(cè)試才來決定到底用不用采取下面的幾種優(yōu)化方案之一。試想,如果表格刷新幀率已經(jīng)非常接近60了,但是還想進(jìn)一步采取緩存行高來優(yōu)化項(xiàng)目。很肯定的說,這種做法是不明智的,因?yàn)樗⑿聨室呀?jīng)非常接近60了,即使再怎么優(yōu)化也不可能突破60這個(gè)數(shù)值,反而采取緩存行高的方式會(huì)消耗內(nèi)存,對(duì)整個(gè)項(xiàng)目的優(yōu)化百害而無一利。

CPU、GPU概念

關(guān)于繪圖和動(dòng)畫有兩種處理方式CPU(中央處理器)和GPU(圖形處理器),CPU的工作都在軟件層面,而GPU的在硬件層面。
總的來說,可以使用CPU做任何事情,但是對(duì)于圖像的處理,通常GPU會(huì)更快,所以,我們想盡可能的把屏幕渲染的工作交給硬件去處理,而問題在于GPU并沒有無限制處理的性能,一旦資源用盡,即使CPU并沒有完全占用,GPU性能還是會(huì)下降。所以,目前大多的性能優(yōu)化都是關(guān)于智能利用GPU和CPU,平衡它們之間工作負(fù)載。

離屏渲染

Core Animation可以用來檢測(cè)應(yīng)用內(nèi)的FPS,當(dāng)FPS 低于45的時(shí)候,用戶就會(huì)察覺到到滑動(dòng)有卡頓。理論上60最佳,實(shí)際過程中59就可以了。

instruments工具中的Core Animation工具(如下圖右下角),也會(huì)出現(xiàn)以下幾個(gè)名詞。接下來分別解釋一下這幾個(gè)名詞:color blended Layers(混合圖層)、color misaligned Layers(圖片的拉伸)、color copied images(圖片的復(fù)制)、color offScreen-Rendered Yellow(離屏渲染)。
Core-Animation.png
  • 離屏渲染:
    是指在屏幕外部不可見部分或異步操作,準(zhǔn)備好圖片。
    優(yōu)點(diǎn):提前畫好圖片。
    缺點(diǎn):會(huì)在CPU和GPU之間頻繁切換,一會(huì)計(jì)算坐標(biāo),一會(huì)畫圖。會(huì)導(dǎo)致CPU消耗高些,但顯示性能稍微好些。一般會(huì)用shadowPath和shouldRasterise(柵格化)來優(yōu)化。

針對(duì)混合圖層和圖片拉升效果引起的性能問題,一般可以通過繪制指定尺寸大小、不透明的圖片來優(yōu)化性能。如下是兩個(gè)代碼片段分別針對(duì)這一點(diǎn)繪制指定尺寸和圓角圖片

  • 繪制圓角圖片
- (UIImage *)imageWithSize:(CGSize )size backColor:(UIColor *)backColor{
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    //1.上下文  ->在內(nèi)存中開辟一個(gè)地址,這和屏幕顯示無關(guān)
    /*
    參數(shù):
    1.繪圖尺寸  
    2.是否不透明:false(透明)/true(不透明),
      第二個(gè)參數(shù),一般設(shè)置為true更好些,會(huì)避免圖層重疊導(dǎo)致的混合渲染  
    3.屏幕的分辨率,
    默認(rèn)如果不指定,默認(rèn)的圖像顯示1.0的分辨率,圖像質(zhì)量不好,
    可以指定為0,會(huì)選擇當(dāng)前屏幕的分辨率
  */
    UIGraphicsBeginImageContextWithOptions(size, YES, 0);
     //2.繪圖 drawInRect就是在指定區(qū)域內(nèi)拉伸屏幕  核心繪圖的重點(diǎn):路徑
    //設(shè)置背景顏色
    [backColor setFill];
    UIRectFill(rect);
    [self drawInRect:rect];
     //3.取得結(jié)果
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    //4.關(guān)閉上下文
    UIGraphicsEndImageContext();

    return image;
}
  • 繪制指定尺寸大小的圖片
- (UIImage *)circleImageWithSize:(CGSize )size 
                    backColor:(UIColor *)backColor 
                     lineColor:(UIColor *)lineColor
                     lineWidth:(CGFloat)linewidth
{
      CGRect rect = CGRectMake(0, 0, size.width, size.height);
    //1.上下文  ->在內(nèi)存中開辟一個(gè)地址,這和屏幕顯示無關(guān)
     /*
    參數(shù):
    1.繪圖尺寸  
    2.是否不透明:false(透明)/true(不透明),
      第二個(gè)參數(shù),一般設(shè)置為true更好些,會(huì)避免圖層重疊導(dǎo)致的混合渲染  
    3.屏幕的分辨率,
    默認(rèn)如果不指定,默認(rèn)的圖像顯示1.0的分辨率,圖像質(zhì)量不好,
    可以指定為0,會(huì)選擇當(dāng)前屏幕的分辨率
  */
    UIGraphicsBeginImageContextWithOptions(size, YES, 0);
    //2.繪圖 drawInRect就是在指定區(qū)域內(nèi)拉伸屏幕  核心繪圖的重點(diǎn):路徑
     //a.背景填充顏色
    [backColor setFill];
    UIRectFill(rect);
    //b.實(shí)例化一個(gè)圓形的路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:rect];
     //c.進(jìn)行路徑裁剪 --后續(xù)的繪圖,都會(huì)在圓形路徑內(nèi)部,外部的全部干掉
    [path addClip];
    //d.繪圖
    [self drawInRect:rect];
     //f.繪制邊線
    [lineColor setStroke];
    path.lineWidth = linewidth;
    [path stroke];

    //3.取得結(jié)果
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    //4.關(guān)閉上下文
    UIGraphicsEndImageContext();

    return image;

}

TableViewCell的優(yōu)化

  • tableViewCell復(fù)用機(jī)制
  • 緩存行高
  • 設(shè)計(jì)統(tǒng)一規(guī)格的cell,擅用hidden來顯示/隱藏subviews,而不是動(dòng)態(tài)的通過addsubview去控制。
  • UITableViewCell上的子View的opaque屬性設(shè)為yes
  • 使用局部刷新
  • 減少subviews的數(shù)量
  • 使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight來設(shè)定固定的高,不要請(qǐng)求delegate
  • 使用正確的數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)數(shù)據(jù)
  • 所有的子視圖都要制定背景顏色(如UIViewController中不設(shè)置背景顏色,會(huì)出現(xiàn)卡頓現(xiàn)象)。
  • 所有的顏色都不要使用alpha,一旦涉及alpha就會(huì)涉及多個(gè)圖層渲染的計(jì)算,運(yùn)算量會(huì)很大,對(duì)資源的消耗會(huì)非常巨大。
  • 柵格化:將cell中的所有內(nèi)容,生成一張獨(dú)立的圖像。只要在自定義cell類中的初始化發(fā)放中寫下如下兩行代碼:

self.layer.shadowPath = YES;
self.layer.rasterizationScale = [UIScreen mainScreen].scale;

  • 異步繪制。如果cell布局比較復(fù)雜建議使用異步繪制,其他情況下不建議使用。同樣也是在自定義cell類中的初始化中完成,只要寫上一句代碼即可。self.layer.drawsAsynchronously = YES;

圖片加載

  • 本地圖片加載方式:
    1、[UIImage imageNamed:@""] 優(yōu)點(diǎn):當(dāng)加載時(shí)會(huì)緩存圖片,該方法用一個(gè)指定的名字在系統(tǒng)緩存中查找并返回一個(gè)圖片對(duì)象如果它存在的話。如果緩存中沒有找到相應(yīng)的圖片,這個(gè)方法從指定的文檔中加載然后緩存并返回這個(gè)對(duì)象。
    2、[[UIImage alloc] initWithContentsOfFile:@""]僅加載圖片。
    3、該如何選擇:

如果你要加載一個(gè)大圖片而且是一次性使用,那么就沒必要緩存這個(gè)圖片,用imageWithContentsOfFile足矣,這樣不會(huì)浪費(fèi)內(nèi)存來緩存它。
然而,在圖片反復(fù)重用的情況下imageNamed是一個(gè)好得多的選擇。

編碼過程

  • 延遲加載Views

更多的view意味著更多的渲染,即更多的CPU和內(nèi)存消耗。想象一下一個(gè)用戶點(diǎn)擊一個(gè)按鈕的時(shí)候需要呈現(xiàn)一個(gè)view的場景。有兩種實(shí)現(xiàn)方法:
1、創(chuàng)建并隱藏這個(gè)view當(dāng)這個(gè)screen加載的時(shí)候,當(dāng)需要時(shí)顯示它;
2、當(dāng)需要時(shí)才創(chuàng)建并展示。
每個(gè)方案都有其優(yōu)缺點(diǎn):
用第一種方案的話因?yàn)槟阈枰婚_始就創(chuàng)建一個(gè)view并保持它直到不再使用,這就會(huì)更加消耗內(nèi)存。然而這也會(huì)使你的app操作更敏感因?yàn)楫?dāng)用戶點(diǎn)擊按鈕的時(shí)候它只需要改變一下這個(gè)view的可見性。
第二種方案則相反-消耗更少內(nèi)存,但是會(huì)在點(diǎn)擊按鈕的時(shí)候比第一種稍顯卡頓。

  • 重用大開銷對(duì)象

一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。可以通過添加屬性到你的class里或者創(chuàng)建靜態(tài)變量(對(duì)象會(huì)在你的app運(yùn)行時(shí)一直存在于內(nèi)存中,和單例(singleton)很相似)來實(shí)現(xiàn)。

  • 選擇正確的數(shù)據(jù)格式,避免反復(fù)處理數(shù)據(jù)
  • 選擇正確的數(shù)據(jù)存儲(chǔ)選項(xiàng)

數(shù)據(jù)存儲(chǔ)大致分plist、對(duì)象歸檔、sqlite。NSUserDefault適合存儲(chǔ)小量數(shù)據(jù),私密信息使用Keychain, sqlite適合大量數(shù)據(jù),歸檔性能較低,盡量避免使用。

處理內(nèi)存警告

UIKit提供了幾種收集低內(nèi)存警告的方法:
1、在app delegate中使用applicationDidReceiveMemoryWarning: 的方法
2、在你的自定義UIViewController的子類(subclass)中覆蓋didReceiveMemoryWarning
3、注冊(cè)并接收 UIApplicationDidReceiveMemoryWarningNotification 的通知

代碼優(yōu)化

  • 良好的編碼習(xí)慣,遵循代碼規(guī)范、mvc架構(gòu)、利用第三方AFN時(shí),做一層網(wǎng)絡(luò)隔離,減少對(duì)第三方的依賴
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、如何提高一個(gè)應(yīng)用程序的性能?1、使用ARC減少內(nèi)存失誤,dealloc需要重寫并對(duì)屬性置nil。2、重用。3、...
    金歌漫舞閱讀 1,064評(píng)論 2 6
  • 一. 如何讓你的應(yīng)用程序更加省電?答:(1). 如果程序用到定位,需要在定位完畢之后關(guān)閉定位,或者降低定位的頻率,...
    Hevin_Chen閱讀 1,236評(píng)論 0 4
  • 1.啟動(dòng)時(shí)間 應(yīng)用啟動(dòng)時(shí)間長短對(duì)用戶第一次體驗(yàn)至關(guān)重要,同時(shí)系統(tǒng)對(duì)應(yīng)用的啟動(dòng)、恢復(fù)等狀態(tài)的運(yùn)行時(shí)間也有嚴(yán)格的要求,...
    心至靜行至遠(yuǎn)閱讀 1,616評(píng)論 2 4
  • 最近研究了一下微博,發(fā)現(xiàn)微博列表中可以優(yōu)化的點(diǎn)相當(dāng)多,先將比較容易優(yōu)化的點(diǎn)羅列如下: 預(yù)排版當(dāng)獲取到 API JS...
    深度碼農(nóng)患者閱讀 1,656評(píng)論 0 12
  • 孔子是誰?相信大家都知道,現(xiàn)在隨便在路邊問一個(gè)人,肯定沒有不知道的,就連路邊要飯吃的至少也知道有這么一個(gè)人??鬃?,...
    大黃蜂BigYellowBee閱讀 671評(píng)論 0 1

友情鏈接更多精彩內(nèi)容