在開發iOS應用程序時,讓程序具備良好的性能是很是關鍵的。這也是用戶所指望的,若是你的程序運行遲鈍或緩慢,會招致用戶的差評。然而因爲iOS設備的侷限性,有時候要想得到良好的性能,是很困難的。在開發過程當中,有許多事項須要記住,而且關於性能影響很容易就忘記。ios
本文收集了25個關於能夠提高程序性能的提示和技巧,把性能優化技巧分爲3個不一樣的等級:初級、中級和高級編程
初級數組
在開發過程當中,下面這些初級技巧須要時刻注意:緩存
1.使用ARC進行內存管理
2.在適當的狀況下使用reuseIdentifier
3.儘量將View設置爲不透明(Opaque)
4.避免臃腫的XIBs
5.不要阻塞主線程性能優化
6.讓圖片的大小跟UIImageView同樣
7.選擇正確的集合
8.使用GZIP壓縮服務器
1) 使用ARC進行內存管理網絡
ARC是在iOS 5中發佈的,它解決了最多見的內存泄露問題——也是開發者最容易健忘的。ARC的全稱是「Automatic Reference Counting」——自動引用計數,它會自動的在代碼中作retain/release工做,開發者不用再手動處理。多線程
下面是建立一個View通用的一些代碼塊:app
- UIView *view = [[UIView alloc] init];
- // ...
- [self.view addSubview:view];
- [view release];
在上面代碼結束的地方很容易會忘記調用release。不過當使用ARC時,ARC會在後臺自動的幫你調用release。
ARC除了能避免內存泄露外,還有助於程序性能的提高:當程序中的對象再也不須要的時候,ARC會自動銷燬對象。因此,你應該在工程中使用ARC。
下面是學習ARC的一些資源:
Tony Dahbura的如何在Cocos2D 2.X工程中使用ARC
若是你仍然不肯定ARC帶來的好處,那麼看一些這篇文章:8個關於ARC的神話——這可以讓你相信你應該在工程中使用ARC!
值得注意的是,ARC並不能避免全部的內存泄露。使用ARC以後,工程中可能還會有內存泄露,不過引發這些內存泄露的主要緣由是:block,retain循環,對CoreFoundation對象(一般是C結構)管理不善,以及真的是代碼沒寫好。
這裏有一篇文章是介紹哪些問題是ARC不能解決的 — 以及如何處理這些問題。
2) 在適當的狀況下使用reuseIdentifier
在適當的狀況使用reuseIdentifier
在iOS程序開發中一個廣泛性的錯誤就是沒有正確的爲UITableViewCells、UICollectionViewCells和UITableViewHeaderFooterViews設置reuseIdentifier。
爲了得到最佳性能,當在tableView:cellForRowAtIndexPath:方法中返回cell時,table view的數據源通常會重用UITableViewCell對象。table view維護着UITableViewCell對象的一個隊列或者列表,這些數據源已經被標記爲重用了。
若是沒有使用reuseIdentifier會發生什麼?若是你在程序中沒有使用reuseIdentifier,table view每次顯示一個row時,都會配置一個全新的cell。這實際上是一個很是消耗資源的操做,而且會影響程序中table view滾動的效率。
自iOS 6以來,你可能還但願header和footer views,以及UICollectionView的cell和supplementary views。
爲了使用reuseIdentifiers,在table view請求一個新的cell時,在數據源中調用下面的方法:
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
若是table view維護的UITableViewCell隊列或列表中有可用的cell,則從隊列從移除一個已經存在的cell,若是沒有的話,就從以前註冊的nib文件或類中建立一個新的cell。若是沒有能夠重用的cell,而且沒有註冊nib文件或類,tableview的dequeueReusableCellWithIdentifier:方法會返回一個nil。
3) 儘量將View設置爲不透明(Opaque)
儘可能將view設置爲Opaque
若是view是不透明的,那麼應該將其opaque屬性設置爲YES。爲何要這樣作呢?這樣設置可讓系統以最優的方式來繪製view。opaque屬性能夠在Interface Builder或代碼中設置。
蘋果的官方文檔對opaque屬性有以下解釋:
This property provides a hint to the drawing system as to how it should treat the view. If set to YES, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance. If set to NO, the drawing system composites the view normally with other content. The default value of this property is YES.
(opaque屬性提示繪製系統如何處理view。若是opaque設置爲YES,繪圖系統會將view看爲徹底不透明,這樣繪圖系統就能夠優化一些繪製操做以提高性能。若是設置爲NO,那麼繪圖系統結合其它內容來處理view。默認狀況下,這個屬性是YES。)
若是屏幕是靜止的,那麼這個opaque屬性的設置與否不是一個大問題。可是,若是view是嵌入到scroll view中的,或者是複雜動畫的一部分,不將設置這個屬性的話確定會影響程序的性能!能夠經過模擬器的Debug\Color Blended Layers選項來查看哪些view沒有設置爲不透明。爲了程序的性能,儘量的將view設置爲不透明!
4) 避免臃腫的XIBs
避免臃腫的XIBs
在iOS 5中開始使用Storyboards,而且將替代XIBs。不過在有些狀況下XIBs仍然有用。若是你的程序須要運行在裝有iOS 5以前版本的設備上,或者要自定義可重用的view,那麼是避免不了要使用XIBs的。
若是必需要使用XIBs的話,儘可能讓XIBs文件簡單。而且每一個view controller對於一個XIB文件,若是能夠的話,把一個view controller的view不一樣的層次單獨分到一個XIBs文件中。
(注意:當把一個XIB文件加載到內存時,XIB文件中的全部內容都將被加載到內存中,包括圖片。若是有一個view還不當即使用的話,就會形成內存的浪費。而這在storyboard中是不會發生的,由於storyboard還在須要的時候才實例化一個view controller。)
當加載XIB時,全部涉及到的圖片都將被緩存,而且若是是開發的程序是針對OS X的話,聲音文件也會被加載。蘋果的官方文檔這樣說:
When you load a nib file that contains references to image or sound resources, the nib-loading code reads the actual image or sound file into memory and and caches it. In OS X, image and sound resources are stored in named caches so that you can access them later if needed. In iOS, only image resources are stored in named caches. To access images, you use the imageNamed: method of NSImage or UIImage, depending on your platform.
(當加載一個nib文件時,也會將nib文件涉及到的圖片或聲音資源加載到內存中,nib-loading代碼會將實際的圖片或聲音文件讀取到內存中,並一直緩存着。在OS X中,圖片和聲音資源都存儲在命名緩存中,這樣以後若是須要的話,能夠對其進行訪問。在iOS中,只有圖片資源被存儲到命名緩存中。要訪問圖片的話,使用NSImage或UIImage(根據不一樣的系統)的imageNamed:方法便可。)
顯然,在使用storyboard時也會發生相似的緩存操做;不過我沒有找到相關內容的任何資料。想要學習storyboard的更多知識嗎?能夠看看Matthijs Hollemans寫的iOS 5中:初級Storyboard Part 1和Part2。
5) 不要阻塞主線程
永遠都不要在主線程作繁重的任務。由於UIKit的左右任務都在主線程中進行,例如繪製、觸摸管理和輸入響應。
在主線程作全部任務的風險是:若是你的代碼阻塞了主線程,那麼程序將出現反應遲鈍。這回招致用戶在App Store上對程序的差評!
在執行I/O操做中,大多數狀況下都會祖塞主線程,這些操做須要從讀寫外部資源,例如磁盤或者網絡。
關於網絡操做可使用NSURLConnection的以下方法,以異步的方式來執行:
- + (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
或者使用第三方框架,例如AFNetworking。
若是你須要作一些其它類型開銷很大的操做(例如執行一個時間密集型的計算或者對磁盤進行讀寫),那麼就使用GCD(Grand Central Dispatch),或NSOperations 和 NSOperationQueues。
下面的代碼是使用GCD的一個模板:
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- // switch to a background thread and perform your expensive operation
- dispatch_async(dispatch_get_main_queue(), ^{
- // switch back to the main thread to update your UI
- });
- });
如上代碼,爲何在第一個dispatch_async裏面還嵌套了一個dispatch_async呢?這是由於關於UIKit相關的代碼須要在主線程裏面執行。
能夠看看Ray Wenderlich中的教程:iOS中多線程和GCD—初級,以及Soheil Azarpour的如何使用NSOperations和NSOperationQueues教程。
6) 讓圖片的大小跟UIImageView同樣
確保圖片和UIImageView大小一致
若是須要將程序bundle中的圖片顯示到UIImageView中,請確保圖片和UIImageView的大小是同樣的。由於圖片的縮放很是耗費資源,特別是將UIImageView嵌入到UIScrollView中。
若是是從遠程服務中下載圖片,有時候你控制不了圖片的尺寸,或者在下載以前沒法在服務器上進行圖片的縮放。這種狀況,當圖片下載完以後,你能夠手動進行圖片的縮放——作好是在後臺線程中!——而後再在UIImageView中使用縮放過的圖片。
7) 選擇正確的集合
選擇正確的集合
學習使用最適合的類或對象是編寫高效代碼的基礎。特別是在處理集合數據時,尤其重要。
蘋果的官網上有一篇文章:集合編程主題( Collections Programming Topics)——詳細的介紹了在集合數據中可使用的類,以及什麼狀況下使用哪一個類。在使用集合時,每一個開發者都應該閱讀一下這個文檔。
太長,不想閱讀(TLDR)?下面是常見集合類型的一個簡介:
•數組:是一個值按順序排列的一個列表。根據索引能夠快速查找,不過根據值進行查找就比較慢,另外插入和刪除也比較慢。
•字典: 存儲鍵/值對。根據鍵能夠快速查找。
•Sets: 是一個值無序排列的列表,根據值能夠快速查找,另外插入和刪除也比較快。
8) 使用GZIP壓縮
使用GZIP壓縮
愈來愈多的程序依賴於外部數據,這些數據通常來自遠程服務器或者其它的外部APIs。有時候你須要開發一個程序來下載一些數據,這些數據能夠是XML,JSON,HTML或者其它一些文本格式。
問題是在移動設備上的網絡是不肯定的。用戶的設備可能在EDGE網絡一分鐘,而後接着又在3G網絡中。無論在什麼狀況下,都不要讓用戶等待。
有一個能夠優化的選擇:使用GZIP對網絡傳輸中的數據進行壓縮,這樣能夠減少文件的大小,並加快下載的速度。壓縮對於文本數據特別有用,由於文本具備很高的壓縮比。
iOS中,若是使用NSURLConnection,那麼默認狀況下已經支持GZIP壓縮了,而且基於NSURLConnection的框架頁支持GZIP壓縮,如AFNetworking。甚至有些雲服務提供商已經提供發送經壓縮過的響應內容,例如Google App Engine。
這裏有一篇關於GZIP壓縮很好的文章,介紹瞭如何在Apache活IIS服務器中開啓支持GZIP壓縮。