IOS 效能優化
最近工作比較空閒,相信我不說大家都知道效能優化的重要性了吧,很多面試公司都有的要求。這也是作為一個高階軟體開發工程師的必備技能 。
zero 卡頓是我們經常遇到的問題,這裡就要提到GPU/CPU了
1.為什麼會卡頓,在此期間GPU/CPU都做了哪些工作吶?
- CPU:物件的建立/銷燬/屬性的調整/佈局計算/文字的計算和排版/圖片格式轉換和解碼,影象的繪製
- GPU 影象處理器,主要進行紋理的渲染。(紋理是GPU所能識別的一種影象格式)
- IOS是雙快取機制,包括前幀快取,後幀快取
- CPU通過一系列的計算,然後GPU去渲染,通過幀快取之後被視訊控制器讀取,最後顯示到螢幕上。成像的原理是通過水平同步訊號+垂直同步訊號一幀幀的繪製而成。
- 卡頓的原因:由於CPU要先計算-GPU渲染,假如CPU/GPU處理的事情較多,在固定的幀率下,未完成需要處理的事情,此時垂直同步訊號已經到來,兩者交叉就會造成視覺上的卡頓
2.卡頓優化
- 儘量減少CPU/GPU的資源消耗
- 不要頻繁的呼叫UIView的相關屬性,如frame/bounds/tranform等
- 儘量提前計算好佈局,在有需要的時候一次性調整對應的屬性
- 儘量吧耗時操作(文字尺寸計算/繪製,圖片解碼/繪製)放到子執行緒處理,同時我們在處理執行緒的時候要注意執行緒的最大併發數量
one tableView的快取
1.說到快取,大家想到的是不是tableviewcell的快取機制吶
TableViewCell 複用
在cellForRowAtIndexPath:
cell
,不繫結資料。在willDisplayCell: forRowAtIndexPath:
的時候繫結資料(賦值)。
2.TableViewCell
在tableView
滑動時,會不斷呼叫heightForRowAtIndexPath:
,當 cell
高度需要自適應時,每次回撥都要計算高度,會導致 UI 卡頓。為了避免重複無意義的計算,需要快取高度。
怎麼快取
- 字典,NSCache。它可以自動清理系統佔用記憶體且是執行緒安全的。自動清理時機:往cache內新增新內容時,以及發生記憶體警告時。
- UITableView-FDTemplateLayoutCell
- 快取高度可以避免無意義的計算。自適應高度的計算。推薦sunny的一篇文章請
Two 記憶體問題
1.常見的問題如下:迴圈引用,webView的記憶體洩漏
在IOS 4.2 以後蘋果引用了ARC,但是ARC本質與MRC一致,都是通過引用計數管理記憶體的。但是ARC也不是萬能的。也會為了程式的正常執行,會隱式的持有或複製物件。這樣變容易造成記憶體洩漏。其中最常見的就是block的迴圈引用問題(解決方法這裡我就不多解釋了)
2.AFnetworking 的記憶體洩漏問題
使用AF的都知道,需要使用到AFHTTPSessionManager的例項物件。 [AFHTTPSessionManager manager] 我一般都是這樣獲取的,不知道你們是怎樣獲取的。但是通過Instrcument工具分析,看到他會出現記憶體洩漏。解決方法如下:
2.1 給它寫個單例
+ (AFHTTPSessionManager *)sharedHTTPSession{
static AFHTTPSessionManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [AFHTTPSessionManager manager];
return manager;
}
2.2 demo推薦的使用方法
@import AFNetworking;
@interface AFAppDotNetAPIClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
@end
#import "AFAppDotNetAPIClient.h"
static NSString * const AFAppDotNetAPIBaseURLString = @"https://api.app.net/";
@implementation AFAppDotNetAPIClient
+ (instancetype)sharedClient {
static AFAppDotNetAPIClient *_sharedClient = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedClient = [[AFAppDotNetAPIClient alloc] initWithBaseURL:[NSURL URLWithString:AFAppDotNetAPIBaseURLString]];
_sharedClient.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
});
return _sharedClient;
3.避免主執行緒堵塞
在主執行緒中避免複雜的計算堵塞主執行緒,造成卡頓
4.圖片的處理
通常imageNamed :載入mainbundle圖片時,函式會快取載入的image。對於那麼使用較少的圖片,消耗記憶體較大 ,所以啟動圖片設定時,建議使用initWithContentsOfFile:函式。
5. 重用開銷大的物件
NSDateFormatter/NSCalendar 特別消耗記憶體,因為他們的初始化很慢。所以你可以在類中申明一個屬性或者懶載入一個他們的例項。
6.選擇合適的資料儲存
- 使用`NSUerDefaults`-只能用來儲存小資料
- 使用XML, JSON, 或者 plist - XML 需要讀取整個檔案到記憶體裡去解析
- 使用NSCoding存檔- 需要讀取檔案
- 使用類似SQLite的本地SQL資料庫
- 使用 Core Data - 蘋果建議使用。與SQLite相比效能沒啥區別。如果使用SQLite的話建議看下Realm框架。
7.啟動時間(這個會在APP啟動優化詳細介紹)
啟動時間很重要,就像人的第一印象,避免啟動頁中使用龐大的XIB。儘量避免耗時操作,如果需要資料請求的話,儘量在子執行緒進行
8.學會處理記憶體警告
UIKit提供了幾種收集低記憶體警告的方法:
- 在app delegate中使用`applicationDidReceiveMemoryWarning:` 的方法
- 在你的自定義UIViewController的子類(subclass)中覆蓋`didReceiveMemoryWarning`
- 註冊並接收 UIApplicationDidReceiveMemoryWarningNotification 的通知
在這些方法中處理,比如清掉快取,否則的話會被系統幹掉你的應用。
耗電優化
1.耗電的主要來源
- 影象處理
- 定位服務
- 網路請求
- CPU處理
2.耗電優化
- 圖片設定圓角的時候儘量讓美工提供圖片,使用maskToBounds及layer.clipToBounds都會有很大的資源消耗
- 一直在後臺定位重新整理位置
- 減少定時器的使用
- 減少I/O操作,不要頻繁寫入小資料,儘量一次讀取。讀取大資料時可以使用dispatch_io,它會優化磁碟訪問。資料量較大時,建議使用資料庫。
- 網路優化:減少網路請求的次數,如果資料多次都是相同建議使用快取。使用斷點續傳下載資料。讓使用者取消長時間執行或者網路慢的網路操作,設定合適的網路超時時間。