iOS 項目優化

前言

近期正處於一段工做空白區,也想着學習學習一下項目優化,因此就本身的項目出手,一步一步地優化項目。html

1、項目結構與應用包瘦身

項目結構

項目自己首先劃分功能區以PageCoreApp劃分python

  • Page存儲應用的模塊,包含首頁我的中心等,每一個模塊下再以ControllerViewModel劃分
  • Core 存儲着一些與項目業務、界面無關的類,包括分類宏定義封裝的請求基類
  • App則存儲着一些與項目相關的類,包括APIBase基類

應用包瘦身

一、首先找出項目中未使用的圖片:

這裏使用了python腳本 腳本地址 找出項目中未使用的圖片,結果不是很是準確,可是能夠自行判斷(存在圖片使用是根據服務端返回顯示的狀況等)git

使用方法:
  1. 下載連接的unUseImage.py文件
  2. 修改項目路徑以及輸出路徑
  3. 終端執行 python unUseImage.py 使用後會在路徑裏輸出文件:
    未使用圖片

後面發現 這個工具 您能夠試試

二、圖片無損壓縮

這裏使用工具 ImageOptim ,點擊連接下載 將項目圖片拖入優化便可 優化結果: github

圖片壓縮

三、代碼瘦身

這裏推薦使用LinkMap,能夠知道項目中各個類的大小,以權衡是否有替換方案 數組

LinkMap

四、 使用 fui 找到應用中未使用的類

安裝fui性能優化

sudo gem install fui -n /usr/local/bin
複製代碼

到項目中使用bash

fui find
複製代碼

便可找出未引用的類,自行判斷刪除便可 #####優化前與優化後的ipa包大小對比 iphone

優化前

優化後

2、項目性能優化

內存

使用instruments leaks 檢測 打開:工具

  1. Product -> Profile -> Leaks
  2. 點擊CellTree、下方篩選
  3. 定位泄漏代碼,修改
    Leaks

內存泄漏
工具只是輔助你尋找泄漏的地方,具體是否泄漏還須要自行判斷

卡頓

在性能優化中一個最具參考價值的屬性是FPS:全稱Frames Per Second,其實就是屏幕刷新率,蘋果的iphone推薦的刷新率是60Hz,也就是說GPU每秒鐘刷新屏幕60次,這每刷新一次就是一幀frame,FPS也就是每秒鐘刷新多少幀畫面。靜止不變的頁面FPS值是0,這個值是沒有參考意義的,只有當頁面在執行動畫或者滑動的時候,FPS值才具備參考價值,FPS值的大小體現了頁面的流暢程度高低,當低於45的時候卡頓會比較明顯。性能

這裏使用Core Animation來檢測,注:需使用真機

打開: 一、Product -> Profile -> Core Animation 二、啓動應用 三、滑動查看FPS值

FPS
卡頓優化:

一、Color Blended Layers (圖層混合)

這個選項是檢測哪裏發生了圖層混合,先介紹一下什麼是圖層混合?不少狀況下,界面都是會出現多個UI控件疊加的狀況,若是有透明或者半透明的控件,那麼GPU會去計算這些這些layer最終的顯示的顏色,也就是咱們肉眼所看到的效果。例如一個上層Veiw顏色是綠色RGB(0,255,0),下層又放了一個View顏色是紅色RGB(0,0,255),透明度是50%,那麼最終顯示到咱們眼前的顏色是藍色RGB(0,127.5,127.5)。這個計算過程會消耗必定的GPU資源損耗性能。若是咱們把上層的綠色View改成不透明, 那麼GPU就不用耗費資源計算,直接顯示綠色。 若是出現圖層混合了,打開Color Blended Layers選項,那塊區域會顯示紅色,因此咱們調試的目的就是將紅色區域消減的越少越好。那麼如何減小紅色區域的出現呢?只要設置控件不透明便可。

  1. 設置opaque 屬性爲true。
  2. 給View設置一個不透明的顏色,沒有特殊須要設置白色便可。

eg:

運行應用 在模擬器中找到:

Color Blended Layers
顯示運行後的界面:
混合圖層
出現了許多混合圖層,咱們就是要消除這些紅色

TIP:當UILabel的內容是中文,須要添加一句 label.layer.masksToBounds = YES,由於當UILabel的內容爲中文時,label實際渲染區域要大於label的size,最外層多了一個sublayer,若是不設置第二行label的邊緣外層灰出現圖層混合的紅色,所以須要在label內容是中文的狀況下加第二句。單獨使用label.layer.masksToBounds = YES是不會發生離屏渲染的

注:xib 也能夠直接設置 masksToBounds 在控件的:

xib.masksToBounds
點擊 +號添加 layer.masksToBounds 打鉤便可 優化後的界面:
Color Blended Layers 優化後
相比以前,清爽了很多,圖片還需美工提供的圖片爲無透明的圖片。

二、Color Misaligned Images(圖片大小)

這個選項能夠幫助咱們查看圖片大小是否正確顯示。若是image size和imageView size不匹配,image會出現黃色。要儘量的減小黃色的出現,由於image size與imageView size不匹配,會消耗資源壓縮圖片。 選擇:

image.png
若是圖片出現黃色,可自行將圖片壓縮至ImageView大小

三、Color Offscreen-Rendered Yellow(離屏渲染)

離屏渲染Off-Screen Rendering 指的是GPU在當前屏幕緩衝區之外新開闢一個緩衝區進行渲染操做。還有另一種屏幕渲染方式-當前屏幕渲染On-Screen Rendering ,指的是GPU的渲染操做是在當前用於顯示的屏幕緩衝區中進行。 離屏渲染會先在屏幕外建立新緩衝區,離屏渲染結束後,再從離屏切到當前屏幕, 把離屏的渲染結果顯示到當前屏幕上,這個上下文切換的過程是很是消耗性能的,實際開發中儘量避免離屏渲染。 觸發離屏渲染Offscreen rendering的行爲:

  • drawRect:方法
  • layer.shadow
  • layer.allowsGroupOpacity or layer.allowsEdgeAntialiasing
  • layer.shouldRasterize
  • layer.mask
  • layer.masksToBounds && layer.cornerRadius

eg:

運行項目,打開:

Color Off-screen Rendered
項目中,此處顯示黃色:
離屏渲染

在切圓角時,使用了layer.masksToBounds && layer.cornerRadius 這裏咱們換一種實現方式,使用貝塞爾曲線畫一個邊框Layer覆蓋在上面即解決了離屏渲染

UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:rect  byRoundingCorners:UIRectCornerAllCorners  cornerRadii:CGSizeMake(cornerRadius, cornerRadius)];
    CAShapeLayer *strokeLayer = [CAShapeLayer layer];
    strokeLayer.path = maskPath.CGPath;
    strokeLayer.fillColor = [UIColor clearColor].CGColor; //內容填充的顏色設置爲clear
    strokeLayer.strokeColor = kWhiteColor.CGColor; //邊色
    strokeLayer.lineWidth = 1; // 邊寬
    [self.layer addSublayer:strokeLayer];
複製代碼

網上還有許多方式能夠設置圓角:

  1. UIBezierPath + Core Graphics切圓角
  2. UIBezierPath + Core Graphics覆蓋鏤空圖片在四角 等等 處理後的效果:
    處理離屏渲染後
優化後的FPS

優化後FPS

3、使用RunTime 儘可能避免 crash

程序運行中不免會出現崩潰,這裏咱們可使用runtime儘可能避免一些常見的崩潰錯誤: #####eg: 給NSArray 替換 objectAtIndex:方法

+ (void)load {
    [NSClassFromString(@"__NSArrayI") swapMethod:@selector(objectAtIndex:) currentMethod:@selector(mq_objectAtIndex:)];
}

- (id)mq_objectAtIndex:(NSUInteger)index
{
    if (index >= [self count])
    {
        return nil;
    }
    return [self mq_objectAtIndex:index];
}

+ (void)swapMethod:(SEL)originMethod currentMethod:(SEL)currentMethod;
{
    Method firstMethod = class_getInstanceMethod(self, originMethod);
    Method secondMethod = class_getInstanceMethod(self, currentMethod);
    method_exchangeImplementations(firstMethod, secondMethod);
}
複製代碼

Load方法替換 objectAtIndexmq_objectAtIndex ,當調用objectAtIndex時會走到mq_objectAtIndex,判斷是否越界,以此來預防數組越界的crash 其餘類像NSDictionary、NSString也能夠自行添加

結語

iOS項目優化還有挺多方面的,包括電池優化、啓動優化等等,筆者這裏就先優化到這裏,若是有需求須要優化的話,會再進行更新,謝謝支持!

相關文章
相關標籤/搜索