ios開發——實用技術篇&開發總結餘建議

來源:互聯網
上載者:User

標籤:

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

 

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

入門級(這是些你一定會經常用在你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的程式碼片段:

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

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

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

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

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

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

static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

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

3.盡量把views設定為不透明

如果你有不透明的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

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. 不要阻塞主線程

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

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

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

你可以使用`NSURLConnection`非同步地做網路操作:

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

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

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

下面代碼是使用GCD的模板

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{// switch to a background thread and perform your expensive operationdispatch_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中調整圖片大小

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

如果圖片是從遠端服務載入的你不能控製圖片大小,比如在下載前調整到合適大小的話,你可以在下載完成後,最好是用backgroundthread,縮放一次,然後在UIImageView中使用縮放後的圖片。

7. 選擇正確的Collection

學會選擇對業務情境最合適的類或者對象是寫出能效高的代碼的基礎。當處理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這些基於它的架構亦然。像GoogleApp 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預設會緩衝資源在記憶體或者儲存中根據它所載入的HTTPHeaders。你甚至可以手動建立一個NSURLRequest然後使它只載入緩衝的值。

下面是一個可用的程式碼片段,你可以可以用它去為一個基本不會改變的圖片建立一個NSURLRequest並緩衝它:

+ (NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; // this will make sure the request always returns the cached imagerequest.HTTPShouldHandleCookies = NO;request.HTTPShouldUsePipelining = YES;[request addValue:@"image}}

這段代碼在每次遍曆後釋放所有autorelease對象

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

24. 選擇是否緩衝圖片

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

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

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

這個方法用一個指定的名字在系統緩衝中尋找並返回一個圖片對象如果它存在的話。如果緩衝中沒有找到相應的圖片,這個方法從指定的文檔中載入然後緩衝並返回這個對象。

相反的,`imageWithContentsOfFile`僅載入圖片。

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

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:

- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp { return [NSDate dateWithTimeIntervalSince1970:timestamp]; }

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

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

 

ios開發——實用技術篇&開發總結餘建議

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.