天天看點

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

轉載自:http://blog.jobbole.com/37984/

  • 首頁
  • 最新文章
  • 資訊
  • 程式員
  • 設計
  • IT技術
  • 創業
  • 在國外
  • 營銷
  • 趣文
  • 特别分享
  • 更多 >

- Navigation - 首頁 最新文章資訊 程式員設計 IT技術創業 在國外營銷 趣文特别分享 更多 >- 工具與資源 - 書籍與教程- 自由職業 - 網際網路 - 管理- 營運 - 人力資源- 職場分享     伯樂線上 >  首頁 >  所有文章 >  程式員 > iOS應用性能調優的25個建議和技巧  

iOS應用性能調優的25個建議和技巧

2013/04/11 | 分類: 程式員 | 6 條評論 | 來源: 伯樂線上     | 标簽: IOS, 性能

分享到:51

寫在前面

本文來自iOS Tutorial Team 的 Marcelo Fabri,他是Movile的一名 iOS 程式員。這是他的個人網站:http://www.marcelofabri.com/,你還可以在Twitter上關注@marcelofabri_。

性能對 iOS 應用的開發尤其重要,如果你的應用失去反應或者很慢,失望的使用者會把他們的失望寫滿App Store的評論。然而由于iOS裝置的限制,有時搞好性能是一件難事。開發過程中你會有很多需要注意的事項,你也很容易在做出選擇時忘記考慮性能影響。

這正是我寫下這篇文章的原因。這篇文章以一個友善檢視的核對表的形式整合了你可以用來提升你app性能的25條建議和技巧。

請耐心讀完這篇文章,為你未來的app提個速!

注意:每在優化代碼之前,你都要注意一個問題,不要養成”預優化”代碼的錯誤習慣。時常使用Instruments去profile你的代碼來發現需要提升的方面。Matt Galloway寫過一篇很棒的如何利用Instruments來優化代碼的文章。

還要注意的是,這裡列出的其中一些建議是有代價的,所建議的方式會提升app的速度或者使它更加高效,但也可能需要花很多功夫去應用或者使代碼變得更加複雜,是以要仔細選擇。

目錄

我要給出的建議将分為三個不同的等級: 入門級、 中級和進階級:

入門級(這是些你一定會經常用在你app開發中的建議)

  • 1. 用ARC管理記憶體
  • 2. 在正确的地方使用reuseIdentifier
  • 3. 盡可能使Views透明
  • 4. 避免龐大的XIB
  • 5. 不要block主線程
  • 6. 在Image Views中調整圖檔大小
  • 7. 選擇正确的Collection
  • 8. 打開gzip壓縮

中級(這些是你可能在一些相對複雜情況下可能用到的)

  • 9. 重用和延遲加載Views
  • 10. Cache, Cache, 還是Cache!
  • 11. 權衡渲染方法
  • 12. 處理記憶體警告
  • 13. 重用大開銷的對象
  • 14. 使用Sprite Sheets
  • 15. 避免反複處理資料
  • 16. 選擇正确的資料格式
  • 17. 正确地設定Background Images
  • 18. 減少使用Web特性
  • 19. 設定Shadow Path
  • 20. 優化你的Table View
  • 21. 選擇正确的資料存儲選項

進階級(這些建議隻應該在你确信他們可以解決問題和得心應手的情況下采用)

  • 22. 加速啟動時間
  • 23. 使用Autorelease Pool
  • 24. 選擇是否緩存圖檔
  • 25. 盡量避免日期格式轉換

無需贅述,讓我們進入正題吧~

初學者性能提升

這個部分緻力于一些能提高性能的基本改變。但所有層次的開發者都有可能會從這個記錄了一些被忽視的項目的小小的性能備忘錄裡獲得一些提升。

1. 用ARC管理記憶體

ARC(Automatic Reference Counting, 自動引用計數)和iOS5一起釋出,它避免了最常見的也就是經常是由于我們忘記釋放記憶體所造成的記憶體洩露。它自動為你管理retain和release的過程,是以你就不必去手動幹預了。

下面是你會經常用來去建立一個View的代碼段:

1 2 3 4

UIView *view = [[UIView alloc] init];

// ...

[self.view addSubview:view];

[view release];

忘掉代碼段結尾的release簡直像記得吃飯一樣簡單。而ARC會自動在底層為你做這些工作。

除了幫你避免記憶體洩露,ARC還可以幫你提高性能,它能保證釋放掉不再需要的對象的記憶體。這都啥年代了,你應該在你的所有項目裡使用ARC!

這裡有一些更多關于ARC的學習資源:

  • Apple’s official documentation
  • Matthijs Hollemans’s Beginning ARC in iOS Tutorial
  • Tony Dahbura’s How To Enable ARC in a Cocos2D 2.X Project
  • If you still aren’t convinced of the benefits of ARC, check out this article on eight myths about ARC to really convince you why you should be using it!

ARC當然不能為你排除所有記憶體洩露的可能性。由于阻塞, retain 周期, 管理不完善的CoreFoundation object(還有C結構)或者就是代碼太爛依然能導緻記憶體洩露。

這裡有一篇很棒的介紹ARC不能做到以及我們該怎麼做的文章 http://conradstoll.com/blog/2013/1/19/blocks-operations-and-retain-cycles.html。

2. 在正确的地方使用 reuseIdentifier

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

一個開發中常見的錯誤就是沒有給UITableViewCells, UICollectionViewCells,甚至是UITableViewHeaderFooterViews設定正确的reuseIdentifier。

為了性能最優化,table view用 `tableView:cellForRowAtIndexPath:` 為rows配置設定cells的時候,它的資料應該重用自UITableViewCell。 一個table view維持一個隊列的資料可重用的UITableViewCell對象。

不使用reuseIdentifier的話,每顯示一行table view就不得不設定全新的cell。這對性能的影響可是相當大的,尤其會使app的滾動體驗大打折扣。

自iOS6起,除了UICollectionView的cells和補充views,你也應該在header和footer views中使用reuseIdentifiers。

想要使用reuseIdentifiers的話,在一個table view中添加一個新的cell時在data source object中添加這個方法:

1 2

static

NSString *CellIdentifier = @

"Cell"

;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

這個方法把那些已經存在的cell從隊列中排除,或者在必要時使用先前注冊的nib或者class創造新的cell。如果沒有可重用的cell,你也沒有注冊一個class或者nib的話,這個方法傳回nil。

3.盡量把views設定為透明

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

如果你有透明的Views你應該設定它們的opaque屬性為YES。

原因是這會使系統用一個最優的方式渲染這些views。這個簡單的屬性在IB或者代碼裡都可以設定。

Apple的文檔對于為圖檔設定透明屬性的描述是:

(opaque)這個屬性給渲染系統提供了一個如何處理這個view的提示。如果設為YES, 渲染系統就認為這個view是完全不透明的,這使得渲染系統優化一些渲染過程和提高性能。如果設定為NO,渲染系統正常地和其它内容組成這個View。預設值是YES。

在相對比較靜止的畫面中,設定這個屬性不會有太大影響。然而當這個view嵌在scroll view裡邊,或者是一個複雜動畫的一部分,不設定這個屬性的話會在很大程度上影響app的性能。

你可以在模拟器中用Debug\Color Blended Layers選項來發現哪些view沒有被設定為opaque。目标就是,能設為opaque的就全設為opaque!

4. 避免過于龐大的XIB

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

iOS5中加入的Storyboards(分鏡)正在快速取代XIB。然而XIB在一些場景中仍然很有用。比如你的app需要适應iOS5之前的裝置,或者你有一個自定義的可重用的view,你就不可避免地要用到他們。

如果你不得不XIB的話,使他們盡量簡單。嘗試為每個Controller配置一個單獨的XIB,盡可能把一個View Controller的view層次結構分散到單獨的XIB中去。

需要注意的是,當你加載一個XIB的時候所有内容都被放在了記憶體裡,包括任何圖檔。如果有一個不會即刻用到的view,你這就是在浪費寶貴的記憶體資源了。Storyboards就是另一碼事兒了,storyboard僅在需要時執行個體化一個view controller.

當家在XIB是,所有圖檔都被chache,如果你在做OS X開發的話,聲音檔案也是。Apple在相關文檔中的記述是:

當你加載一個引用了圖檔或者聲音資源的nib時,nib加載代碼會把圖檔和聲音檔案寫進記憶體。在OS X中,圖檔和聲音資源被緩存在named cache中以便将來用到時擷取。在iOS中,僅圖檔資源會被存進named caches。取決于你所在的平台,使用NSImage 或UIImage 的`imageNamed:`方法來擷取圖檔資源。

很明顯,同樣的事情也發生在storyboards中,但我并沒有找到任何支援這個結論的文檔。如果你了解這個操作,寫信給我!

想要了解更多關于storyboards的内容的話你可以看看 Matthijs Hollemans的Beginning Storyboards in iOS 5 Part 1 和 Part 2

5. 不要阻塞主線程

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

永遠不要使主線程承擔過多。因為UIKit在主線程上做所有工作,渲染,管理觸摸反應,回應輸入等都需要在它上面完成。

一直使用主線程的風險就是如果你的代碼真的block了主線程,你的app會失去反應。這。。。正是在App Store中拿到一顆星的捷徑 :]

大部分阻礙主程序的情形是你的app在做一些牽涉到讀寫外部資源的I/O操作,比如存儲或者網絡。

你可以使用`NSURLConnection`異步地做網絡操作:

+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler

或者使用像 AFNetworking這樣的架構來異步地做這些操作。

如果你需要做其它類型的需要耗費巨大資源的操作(比如時間敏感的計算或者存儲讀寫)那就用 Grand Central Dispatch,或者 NSOperation 和 NSOperationQueues.

下面代碼是使用GCD的模闆

1 2 3 4 5 6 7 8

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`嗎?這是因為任何UIKit相關的代碼需要在主線程上進行。

如果你對 NSOperation 或者GCD 的細節感興趣的話,看看Ray Wenderlich的 Multithreading and Grand Central Dispatch on iOS for Beginners, 還有 Soheil Azarpour 的 How To Use NSOperations and NSOperationQueues 教程。

6. 在Image Views中調整圖檔大小

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

如果要在`UIImageView`中顯示一個來自bundle的圖檔,你應保證圖檔的大小和UIImageView的大小相同。在運作中縮放圖檔是很耗費資源的,特别是`UIImageView`嵌套在`UIScrollView`中的情況下。

如果圖檔是從遠端服務加載的你不能控制圖檔大小,比如在下載下傳前調整到合适大小的話,你可以在下載下傳完成後,最好是用background thread,縮放一次,然後在UIImageView中使用縮放後的圖檔。

7. 選擇正确的Collection

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

學會選擇對業務場景最合适的類或者對象是寫出能效高的代碼的基礎。當處理collections時這句話尤其正确。

Apple有一個 Collections Programming Topics 的文檔詳盡介紹了可用的classes間的差别和你該在哪些場景中使用它們。這對于任何使用collections的人來說是一個必讀的文檔。

呵呵,我就知道你因為太長沒看…這是一些常見collection的總結:

  • Arrays: 有序的一組值。使用index來lookup很快,使用value lookup很慢, 插入/删除很慢。
  • Dictionaries: 存儲鍵值對。 用鍵來查找比較快。
  • Sets: 無序的一組值。用值來查找很快,插入/删除很快。

8. 打開gzip壓縮

大量app依賴于遠端資源和第三方API,你可能會開發一個需要從遠端下載下傳XML, JSON, HTML或者其它格式的app。

問題是我們的目标是移動裝置,是以你就不能指望網絡狀況有多好。一個使用者現在還在edge網絡,下一分鐘可能就切換到了3G。不論什麼場景,你肯定不想讓你的使用者等太長時間。

減小文檔的一個方式就是在服務端和你的app中打開gzip。這對于文字這種能有更高壓縮率的資料來說會有更顯著的效用。

好消息是,iOS已經在NSURLConnection中預設支援了gzip壓縮,當然AFNetworking這些基于它的架構亦然。像Google App Engine這些雲服務提供者也已經支援了壓縮輸出。

如果你不知道如何利用Apache或者IIS(伺服器)來打開gzip,可以讀下這篇文章。

中級性能提升

你确信你已經掌握了前述那些基礎級的優化方案了嗎?但實際情況是,有時一些解決方案并不像那些一樣明顯,它們往往嚴重依賴于你如何架構和書寫你的app。下面的這些建議就是針對這些場景的。

9. 重用和延遲加載(lazy load) Views

更多的view意味着更多的渲染,也就是更多的CPU和記憶體消耗,對于那種嵌套了很多view在UIScrollView裡邊的app更是如此。

這裡我們用到的技巧就是模仿`UITableView`和`UICollectionView`的操作: 不要一次建立所有的subview,而是當需要時才建立,當它們完成了使命,把他們放進一個可重用的隊列中。

這樣的話你就隻需要在滾動發生時建立你的views,避免了不劃算的記憶體配置設定。

建立views的能效問題也适用于你app的其它方面。想象一下一個使用者點選一個按鈕的時候需要呈現一個view的場景。有兩種實作方法:

  • 1. 建立并隐藏這個view當這個screen加載的時候,當需要時顯示它;
  • 2. 當需要時才建立并展示。

每個方案都有其優缺點。

用第一種方案的話因為你需要一開始就建立一個view并保持它直到不再使用,這就會更加消耗記憶體。然而這也會使你的app操作更敏感因為當使用者點選按鈕的時候它隻需要改變一下這個view的可見性。

第二種方案則相反-消耗更少記憶體,但是會在點選按鈕的時候比第一種稍顯示卡頓。

10. Cache, Cache, 還是Cache!

一個極好的原則就是,緩存所需要的,也就是那些不大可能改變但是需要經常讀取的東西。

我們能緩存些什麼呢?一些選項是,遠端伺服器的響應,圖檔,甚至計算結果,比如UITableView的行高。

NSURLConnection預設會緩存資源在記憶體或者存儲中根據它所加載的HTTP Headers。你甚至可以手動建立一個NSURLRequest然後使它隻加載緩存的值。

下面是一個可用的代碼段,你可以可以用它去為一個基本不會改變的圖檔建立一個NSURLRequest并緩存它:

1 2 3 4 5 6 7 8 9 10

+ (NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

// this will make sure the request always returns the cached image

request.HTTPShouldHandleCookies = NO;

request.HTTPShouldUsePipelining = YES;

[request addValue:@

"image

}

}

這段代碼在每次周遊後釋放所有autorelease對象

更多關于NSAutoreleasePool請參考官方文檔。

24. 選擇是否緩存圖檔

常見的從bundle中加載圖檔的方式有兩種,一個是用`imageNamed`,二是用`imageWithContentsOfFile`,第一種比較常見一點。

既然有兩種類似的方法來實作相同的目的,那麼他們之間的差别是什麼呢?

`imageNamed`的優點是當加載時會緩存圖檔。`imageNamed`的文檔中這麼說:

這個方法用一個指定的名字在系統緩存中查找并傳回一個圖檔對象如果它存在的話。如果緩存中沒有找到相應的圖檔,這個方法從指定的文檔中加載然後緩存并傳回這個對象。

相反的,`imageWithContentsOfFile`僅加載圖檔。

下面的代碼說明了這兩種方法的用法:

1 2 3

UIImage *img = [UIImage imageNamed:@

"myImage"

];

// caching

// or

UIImage *img = [UIImage imageWithContentsOfFile:@

"myImage"

];

// no caching

那麼我們應該如何選擇呢?

如果你要加載一個大圖檔而且是一次性使用,那麼就沒必要緩存這個圖檔,用`imageWithContentsOfFile`足矣,這樣不會浪費記憶體來緩存它。

然而,在圖檔反複重用的情況下`imageNamed`是一個好得多的選擇。

25. 避免日期格式轉換

如果你要用`NSDateFormatter`來處理很多日期格式,應該小心以待。就像先前提到的,任何時候重用`NSDateFormatters`都是一個好的實踐。

然而,如果你需要更多速度,那麼直接用C是一個好的方案。Sam Soffes有一個不錯的文章(http://soff.es/how-to-drastically-improve-your-app-with-an-afternoon-and-instruments)裡面有一些可以用來解析ISO-8601日期字元串的代碼,簡單重寫一下就可以拿來用了。

嗯,直接用C來搞,看起來不錯了,但是你相信嗎,我們還有更好的方案!

如果你可以控制你所處理的日期格式,盡量選擇Unix時間戳。你可以友善地從時間戳轉換到NSDate:

1 2 3

- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {

return

[NSDate dateWithTimeIntervalSince1970:timestamp];

}

這樣會比用C來解析日期字元串還快!

需要注意的是,許多web API會以微秒的形式傳回時間戳,因為這種格式在javascript中更友善使用。記住用`dateFromUnixTimestamp`之前除以1000就好了。

更多閱讀

下列這些WWDC視訊強烈推薦給想要提高app性能的開發者。你首先需要保證你有使你的Apple ID注冊為一個開發者身份才能看在這裡看WWDC 2012的視訊。

  • #406: Adopting Automatic Reference Counting
  • #238: iOS App Performance: Graphics and Animations
  • #242: iOS App Performance: Memory
  • #235: iOS App Performance: Responsiveness
  • #409: Learning Instruments
  • #706: Networking Best Practices
  • #514: OpenGL ES Tools and Techniques
  • #506: Optimizing 2D Graphics and Animation Performance
  • #601: Optimizing Web Content in UIWebViews and Websites on iOS
  • #225: Up and Running: Making a Great Impression with Every Launch

一些01年的WWDC視訊也很有價值:

  • #308: Blocks and Grand Central Dispatch in Practice
  • #323: Introducing Automatic Reference Counting
  • #312: iOS Performance and Power Optimization with Instruments
  • #105: Polishing Your App: Tips and tricks to improve the responsiveness and performance
  • #121: Understanding UIKit Rendering

其它一些值得看的視訊,大部分來自iOS 5 Tech Talks:

  • Your iOS App Performance Hitlist
  • Optimizing App Performance with Instruments
  • Understanding iOS View Compositing

基于《Your iOS App Performance Hitlist》這個Michael Jurewitz的視訊,Ole Begemann寫了一篇文字總結的文章。

Apple提供了一個非常有用的叫做“Performance Tuning | 性能調優”的資源。

–EOF–

英文原文:raywenderlich,感謝@路塔石 的熱心翻譯。:)

譯文連結:http://blog.jobbole.com/37984/

【非特殊說明,轉載必須在正文中标注并保留原文連結、譯文連結和譯者等資訊,謝謝合作!】

  • 首頁
  • 最新文章
  • 資訊
  • 程式員
  • 設計
  • IT技術
  • 創業
  • 在國外
  • 營銷
  • 趣文
  • 特别分享
  • 更多 >

- Navigation - 首頁 最新文章資訊 程式員設計 IT技術創業 在國外營銷 趣文特别分享 更多 >- 工具與資源 - 書籍與教程- 自由職業 - 網際網路 - 管理- 營運 - 人力資源- 職場分享     伯樂線上 >  首頁 >  所有文章 >  程式員 > iOS應用性能調優的25個建議和技巧  

iOS應用性能調優的25個建議和技巧

2013/04/11 | 分類: 程式員 | 6 條評論 | 來源: 伯樂線上     | 标簽: IOS, 性能

分享到:51

寫在前面

本文來自iOS Tutorial Team 的 Marcelo Fabri,他是Movile的一名 iOS 程式員。這是他的個人網站:http://www.marcelofabri.com/,你還可以在Twitter上關注@marcelofabri_。

性能對 iOS 應用的開發尤其重要,如果你的應用失去反應或者很慢,失望的使用者會把他們的失望寫滿App Store的評論。然而由于iOS裝置的限制,有時搞好性能是一件難事。開發過程中你會有很多需要注意的事項,你也很容易在做出選擇時忘記考慮性能影響。

這正是我寫下這篇文章的原因。這篇文章以一個友善檢視的核對表的形式整合了你可以用來提升你app性能的25條建議和技巧。

請耐心讀完這篇文章,為你未來的app提個速!

注意:每在優化代碼之前,你都要注意一個問題,不要養成”預優化”代碼的錯誤習慣。時常使用Instruments去profile你的代碼來發現需要提升的方面。Matt Galloway寫過一篇很棒的如何利用Instruments來優化代碼的文章。

還要注意的是,這裡列出的其中一些建議是有代價的,所建議的方式會提升app的速度或者使它更加高效,但也可能需要花很多功夫去應用或者使代碼變得更加複雜,是以要仔細選擇。

目錄

我要給出的建議将分為三個不同的等級: 入門級、 中級和進階級:

入門級(這是些你一定會經常用在你app開發中的建議)

  • 1. 用ARC管理記憶體
  • 2. 在正确的地方使用reuseIdentifier
  • 3. 盡可能使Views透明
  • 4. 避免龐大的XIB
  • 5. 不要block主線程
  • 6. 在Image Views中調整圖檔大小
  • 7. 選擇正确的Collection
  • 8. 打開gzip壓縮

中級(這些是你可能在一些相對複雜情況下可能用到的)

  • 9. 重用和延遲加載Views
  • 10. Cache, Cache, 還是Cache!
  • 11. 權衡渲染方法
  • 12. 處理記憶體警告
  • 13. 重用大開銷的對象
  • 14. 使用Sprite Sheets
  • 15. 避免反複處理資料
  • 16. 選擇正确的資料格式
  • 17. 正确地設定Background Images
  • 18. 減少使用Web特性
  • 19. 設定Shadow Path
  • 20. 優化你的Table View
  • 21. 選擇正确的資料存儲選項

進階級(這些建議隻應該在你确信他們可以解決問題和得心應手的情況下采用)

  • 22. 加速啟動時間
  • 23. 使用Autorelease Pool
  • 24. 選擇是否緩存圖檔
  • 25. 盡量避免日期格式轉換

無需贅述,讓我們進入正題吧~

初學者性能提升

這個部分緻力于一些能提高性能的基本改變。但所有層次的開發者都有可能會從這個記錄了一些被忽視的項目的小小的性能備忘錄裡獲得一些提升。

1. 用ARC管理記憶體

ARC(Automatic Reference Counting, 自動引用計數)和iOS5一起釋出,它避免了最常見的也就是經常是由于我們忘記釋放記憶體所造成的記憶體洩露。它自動為你管理retain和release的過程,是以你就不必去手動幹預了。

下面是你會經常用來去建立一個View的代碼段:

1 2 3 4

UIView *view = [[UIView alloc] init];

// ...

[self.view addSubview:view];

[view release];

忘掉代碼段結尾的release簡直像記得吃飯一樣簡單。而ARC會自動在底層為你做這些工作。

除了幫你避免記憶體洩露,ARC還可以幫你提高性能,它能保證釋放掉不再需要的對象的記憶體。這都啥年代了,你應該在你的所有項目裡使用ARC!

這裡有一些更多關于ARC的學習資源:

  • Apple’s official documentation
  • Matthijs Hollemans’s Beginning ARC in iOS Tutorial
  • Tony Dahbura’s How To Enable ARC in a Cocos2D 2.X Project
  • If you still aren’t convinced of the benefits of ARC, check out this article on eight myths about ARC to really convince you why you should be using it!

ARC當然不能為你排除所有記憶體洩露的可能性。由于阻塞, retain 周期, 管理不完善的CoreFoundation object(還有C結構)或者就是代碼太爛依然能導緻記憶體洩露。

這裡有一篇很棒的介紹ARC不能做到以及我們該怎麼做的文章 http://conradstoll.com/blog/2013/1/19/blocks-operations-and-retain-cycles.html。

2. 在正确的地方使用 reuseIdentifier

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

一個開發中常見的錯誤就是沒有給UITableViewCells, UICollectionViewCells,甚至是UITableViewHeaderFooterViews設定正确的reuseIdentifier。

為了性能最優化,table view用 `tableView:cellForRowAtIndexPath:` 為rows配置設定cells的時候,它的資料應該重用自UITableViewCell。 一個table view維持一個隊列的資料可重用的UITableViewCell對象。

不使用reuseIdentifier的話,每顯示一行table view就不得不設定全新的cell。這對性能的影響可是相當大的,尤其會使app的滾動體驗大打折扣。

自iOS6起,除了UICollectionView的cells和補充views,你也應該在header和footer views中使用reuseIdentifiers。

想要使用reuseIdentifiers的話,在一個table view中添加一個新的cell時在data source object中添加這個方法:

1 2

static

NSString *CellIdentifier = @

"Cell"

;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

這個方法把那些已經存在的cell從隊列中排除,或者在必要時使用先前注冊的nib或者class創造新的cell。如果沒有可重用的cell,你也沒有注冊一個class或者nib的話,這個方法傳回nil。

3.盡量把views設定為透明

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

如果你有透明的Views你應該設定它們的opaque屬性為YES。

原因是這會使系統用一個最優的方式渲染這些views。這個簡單的屬性在IB或者代碼裡都可以設定。

Apple的文檔對于為圖檔設定透明屬性的描述是:

(opaque)這個屬性給渲染系統提供了一個如何處理這個view的提示。如果設為YES, 渲染系統就認為這個view是完全不透明的,這使得渲染系統優化一些渲染過程和提高性能。如果設定為NO,渲染系統正常地和其它内容組成這個View。預設值是YES。

在相對比較靜止的畫面中,設定這個屬性不會有太大影響。然而當這個view嵌在scroll view裡邊,或者是一個複雜動畫的一部分,不設定這個屬性的話會在很大程度上影響app的性能。

你可以在模拟器中用Debug\Color Blended Layers選項來發現哪些view沒有被設定為opaque。目标就是,能設為opaque的就全設為opaque!

4. 避免過于龐大的XIB

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

iOS5中加入的Storyboards(分鏡)正在快速取代XIB。然而XIB在一些場景中仍然很有用。比如你的app需要适應iOS5之前的裝置,或者你有一個自定義的可重用的view,你就不可避免地要用到他們。

如果你不得不XIB的話,使他們盡量簡單。嘗試為每個Controller配置一個單獨的XIB,盡可能把一個View Controller的view層次結構分散到單獨的XIB中去。

需要注意的是,當你加載一個XIB的時候所有内容都被放在了記憶體裡,包括任何圖檔。如果有一個不會即刻用到的view,你這就是在浪費寶貴的記憶體資源了。Storyboards就是另一碼事兒了,storyboard僅在需要時執行個體化一個view controller.

當家在XIB是,所有圖檔都被chache,如果你在做OS X開發的話,聲音檔案也是。Apple在相關文檔中的記述是:

當你加載一個引用了圖檔或者聲音資源的nib時,nib加載代碼會把圖檔和聲音檔案寫進記憶體。在OS X中,圖檔和聲音資源被緩存在named cache中以便将來用到時擷取。在iOS中,僅圖檔資源會被存進named caches。取決于你所在的平台,使用NSImage 或UIImage 的`imageNamed:`方法來擷取圖檔資源。

很明顯,同樣的事情也發生在storyboards中,但我并沒有找到任何支援這個結論的文檔。如果你了解這個操作,寫信給我!

想要了解更多關于storyboards的内容的話你可以看看 Matthijs Hollemans的Beginning Storyboards in iOS 5 Part 1 和 Part 2

5. 不要阻塞主線程

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

永遠不要使主線程承擔過多。因為UIKit在主線程上做所有工作,渲染,管理觸摸反應,回應輸入等都需要在它上面完成。

一直使用主線程的風險就是如果你的代碼真的block了主線程,你的app會失去反應。這。。。正是在App Store中拿到一顆星的捷徑 :]

大部分阻礙主程序的情形是你的app在做一些牽涉到讀寫外部資源的I/O操作,比如存儲或者網絡。

你可以使用`NSURLConnection`異步地做網絡操作:

+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler

或者使用像 AFNetworking這樣的架構來異步地做這些操作。

如果你需要做其它類型的需要耗費巨大資源的操作(比如時間敏感的計算或者存儲讀寫)那就用 Grand Central Dispatch,或者 NSOperation 和 NSOperationQueues.

下面代碼是使用GCD的模闆

1 2 3 4 5 6 7 8

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`嗎?這是因為任何UIKit相關的代碼需要在主線程上進行。

如果你對 NSOperation 或者GCD 的細節感興趣的話,看看Ray Wenderlich的 Multithreading and Grand Central Dispatch on iOS for Beginners, 還有 Soheil Azarpour 的 How To Use NSOperations and NSOperationQueues 教程。

6. 在Image Views中調整圖檔大小

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

如果要在`UIImageView`中顯示一個來自bundle的圖檔,你應保證圖檔的大小和UIImageView的大小相同。在運作中縮放圖檔是很耗費資源的,特别是`UIImageView`嵌套在`UIScrollView`中的情況下。

如果圖檔是從遠端服務加載的你不能控制圖檔大小,比如在下載下傳前調整到合适大小的話,你可以在下載下傳完成後,最好是用background thread,縮放一次,然後在UIImageView中使用縮放後的圖檔。

7. 選擇正确的Collection

iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

學會選擇對業務場景最合适的類或者對象是寫出能效高的代碼的基礎。當處理collections時這句話尤其正确。

Apple有一個 Collections Programming Topics 的文檔詳盡介紹了可用的classes間的差别和你該在哪些場景中使用它們。這對于任何使用collections的人來說是一個必讀的文檔。

呵呵,我就知道你因為太長沒看…這是一些常見collection的總結:

  • Arrays: 有序的一組值。使用index來lookup很快,使用value lookup很慢, 插入/删除很慢。
  • Dictionaries: 存儲鍵值對。 用鍵來查找比較快。
  • Sets: 無序的一組值。用值來查找很快,插入/删除很快。

8. 打開gzip壓縮

大量app依賴于遠端資源和第三方API,你可能會開發一個需要從遠端下載下傳XML, JSON, HTML或者其它格式的app。

問題是我們的目标是移動裝置,是以你就不能指望網絡狀況有多好。一個使用者現在還在edge網絡,下一分鐘可能就切換到了3G。不論什麼場景,你肯定不想讓你的使用者等太長時間。

減小文檔的一個方式就是在服務端和你的app中打開gzip。這對于文字這種能有更高壓縮率的資料來說會有更顯著的效用。

好消息是,iOS已經在NSURLConnection中預設支援了gzip壓縮,當然AFNetworking這些基于它的架構亦然。像Google App Engine這些雲服務提供者也已經支援了壓縮輸出。

如果你不知道如何利用Apache或者IIS(伺服器)來打開gzip,可以讀下這篇文章。

中級性能提升

你确信你已經掌握了前述那些基礎級的優化方案了嗎?但實際情況是,有時一些解決方案并不像那些一樣明顯,它們往往嚴重依賴于你如何架構和書寫你的app。下面的這些建議就是針對這些場景的。

9. 重用和延遲加載(lazy load) Views

更多的view意味着更多的渲染,也就是更多的CPU和記憶體消耗,對于那種嵌套了很多view在UIScrollView裡邊的app更是如此。

這裡我們用到的技巧就是模仿`UITableView`和`UICollectionView`的操作: 不要一次建立所有的subview,而是當需要時才建立,當它們完成了使命,把他們放進一個可重用的隊列中。

這樣的話你就隻需要在滾動發生時建立你的views,避免了不劃算的記憶體配置設定。

建立views的能效問題也适用于你app的其它方面。想象一下一個使用者點選一個按鈕的時候需要呈現一個view的場景。有兩種實作方法:

  • 1. 建立并隐藏這個view當這個screen加載的時候,當需要時顯示它;
  • 2. 當需要時才建立并展示。

每個方案都有其優缺點。

用第一種方案的話因為你需要一開始就建立一個view并保持它直到不再使用,這就會更加消耗記憶體。然而這也會使你的app操作更敏感因為當使用者點選按鈕的時候它隻需要改變一下這個view的可見性。

第二種方案則相反-消耗更少記憶體,但是會在點選按鈕的時候比第一種稍顯示卡頓。

10. Cache, Cache, 還是Cache!

一個極好的原則就是,緩存所需要的,也就是那些不大可能改變但是需要經常讀取的東西。

我們能緩存些什麼呢?一些選項是,遠端伺服器的響應,圖檔,甚至計算結果,比如UITableView的行高。

NSURLConnection預設會緩存資源在記憶體或者存儲中根據它所加載的HTTP Headers。你甚至可以手動建立一個NSURLRequest然後使它隻加載緩存的值。

下面是一個可用的代碼段,你可以可以用它去為一個基本不會改變的圖檔建立一個NSURLRequest并緩存它:

1 2 3 4 5 6 7 8 9 10

+ (NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

// this will make sure the request always returns the cached image

request.HTTPShouldHandleCookies = NO;

request.HTTPShouldUsePipelining = YES;

[request addValue:@

"image

}

}

這段代碼在每次周遊後釋放所有autorelease對象

更多關于NSAutoreleasePool請參考官方文檔。

24. 選擇是否緩存圖檔

常見的從bundle中加載圖檔的方式有兩種,一個是用`imageNamed`,二是用`imageWithContentsOfFile`,第一種比較常見一點。

既然有兩種類似的方法來實作相同的目的,那麼他們之間的差别是什麼呢?

`imageNamed`的優點是當加載時會緩存圖檔。`imageNamed`的文檔中這麼說:

這個方法用一個指定的名字在系統緩存中查找并傳回一個圖檔對象如果它存在的話。如果緩存中沒有找到相應的圖檔,這個方法從指定的文檔中加載然後緩存并傳回這個對象。

相反的,`imageWithContentsOfFile`僅加載圖檔。

下面的代碼說明了這兩種方法的用法:

1 2 3

UIImage *img = [UIImage imageNamed:@

"myImage"

];

// caching

// or

UIImage *img = [UIImage imageWithContentsOfFile:@

"myImage"

];

// no caching

那麼我們應該如何選擇呢?

如果你要加載一個大圖檔而且是一次性使用,那麼就沒必要緩存這個圖檔,用`imageWithContentsOfFile`足矣,這樣不會浪費記憶體來緩存它。

然而,在圖檔反複重用的情況下`imageNamed`是一個好得多的選擇。

25. 避免日期格式轉換

如果你要用`NSDateFormatter`來處理很多日期格式,應該小心以待。就像先前提到的,任何時候重用`NSDateFormatters`都是一個好的實踐。

然而,如果你需要更多速度,那麼直接用C是一個好的方案。Sam Soffes有一個不錯的文章(http://soff.es/how-to-drastically-improve-your-app-with-an-afternoon-and-instruments)裡面有一些可以用來解析ISO-8601日期字元串的代碼,簡單重寫一下就可以拿來用了。

嗯,直接用C來搞,看起來不錯了,但是你相信嗎,我們還有更好的方案!

如果你可以控制你所處理的日期格式,盡量選擇Unix時間戳。你可以友善地從時間戳轉換到NSDate:

1 2 3

- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {

return

[NSDate dateWithTimeIntervalSince1970:timestamp];

}

這樣會比用C來解析日期字元串還快!

需要注意的是,許多web API會以微秒的形式傳回時間戳,因為這種格式在javascript中更友善使用。記住用`dateFromUnixTimestamp`之前除以1000就好了。

更多閱讀

下列這些WWDC視訊強烈推薦給想要提高app性能的開發者。你首先需要保證你有使你的Apple ID注冊為一個開發者身份才能看在這裡看WWDC 2012的視訊。

  • #406: Adopting Automatic Reference Counting
  • #238: iOS App Performance: Graphics and Animations
  • #242: iOS App Performance: Memory
  • #235: iOS App Performance: Responsiveness
  • #409: Learning Instruments
  • #706: Networking Best Practices
  • #514: OpenGL ES Tools and Techniques
  • #506: Optimizing 2D Graphics and Animation Performance
  • #601: Optimizing Web Content in UIWebViews and Websites on iOS
  • #225: Up and Running: Making a Great Impression with Every Launch

一些01年的WWDC視訊也很有價值:

  • #308: Blocks and Grand Central Dispatch in Practice
  • #323: Introducing Automatic Reference Counting
  • #312: iOS Performance and Power Optimization with Instruments
  • #105: Polishing Your App: Tips and tricks to improve the responsiveness and performance
  • #121: Understanding UIKit Rendering

其它一些值得看的視訊,大部分來自iOS 5 Tech Talks:

  • Your iOS App Performance Hitlist
  • Optimizing App Performance with Instruments
  • Understanding iOS View Compositing

基于《Your iOS App Performance Hitlist》這個Michael Jurewitz的視訊,Ole Begemann寫了一篇文字總結的文章。

Apple提供了一個非常有用的叫做“Performance Tuning | 性能調優”的資源。

–EOF–

英文原文:raywenderlich,感謝@路塔石 的熱心翻譯。:)

譯文連結:http://blog.jobbole.com/37984/

【非特殊說明,轉載必須在正文中标注并保留原文連結、譯文連結和譯者等資訊,謝謝合作!】

  • 上一篇Objective-C中使用@try處理異常
  • 下一篇記憶體管理MRR/ARC,property和記憶體洩露
主題推薦
應用 性能 google app engine 有道雲筆記 遊戲開發者
iOS應用性能調優的25個建議和技巧【轉】iOS應用性能調優的25個建議和技巧iOS應用性能調優的25個建議和技巧

轉載于:https://www.cnblogs.com/gatsbywang/p/4512345.html