iOS應用性能調優的25個建議和技巧javascript
本文來自iOSTutorial Team 的 Marcelo Fabri,他是Movile的一名 iOS 程序猿。這是他的我的站點:http://www.marcelofabri.com/,你還可以在Twitter上關注@marcelofabri_。html
性能對 iOS 應用的開發尤爲重要,假設你的應用失去反應或者很是慢,失望的用戶會把他們的失望寫滿AppStore的評論。然而由於iOS設備的限制,有時搞好性能是一件難事。開發過程當中你會有很是多需要注意的事項。你也很是easy在作出選擇時忘記考慮性能影響。java
這正是我寫下這篇文章的緣由。ios
這篇文章以一個方便查看的核對錶的形式整合了你可以用來提高你app性能的25條建議和技巧。程序員
請耐心讀完這篇文章,爲你將來的app提個速!web
注意:每在優化代碼以前。你都要注意一個問題,不要養成」預優化」代碼的錯誤習慣。時常使用Instruments去profile你的代碼來發現需要提高的方面。數據庫
MattGalloway寫過一篇很是棒的怎樣利用Instruments來優化代碼的文章。編程
還要注意的是,這裏列出的當中一些建議是有代價的。所建議的方式會提高app的速度或者使它更加高效,但也可能需要花很是多功夫去應用或者使代碼變得更加複雜。因此要細緻選擇。json
文件夾xcode
我要給出的建議將分爲三個不一樣的等級:入門級、中級和進階級:
入門級(這是些你必定會經常用在你app開發中的建議)
· 1. 用ARC管理內存
· 2. 在正確的地方使用reuseIdentifier
· 3. 儘量使Views透明
· 4. 避免龐大的XIB
· 5. 不要block主線程
· 6. 在ImageViews中調整圖片大小
· 7. 選擇正確的Collection
· 8. 打開gzip壓縮
中級(這些是你可能在一些相對複雜狀況下可能用到的)
· 9. 重用和延遲載入Views
· 10. Cache, Cache, 仍是Cache。
· 11. 權衡渲染方法
· 12. 處理內存警告
· 13. 重用大開銷的對象
· 14. 使用SpriteSheets
· 15. 避免重複處理數據
· 16. 選擇正確的數據格式
· 17. 正確地設定BackgroundImages
· 18. 下降使用Web特性
· 19. 設定ShadowPath
· 20. 優化你的TableView
· 21. 選擇正確的數據存儲選項
進階級(這些建議僅僅應該在你確信他們可以解決這個問題和駕輕就熟的狀況下採用)
· 22. 加速啓動時間
· 23. 使用AutoreleasePool
· 24. 選擇是否緩存圖片
· 25. 儘可能避免日期格式轉換
無需贅述,讓咱們進入正題吧~
剛開始學習的人性能提高
這個部分致力於一些能提升性能的基本改變。但所有層次的開發人員都有可能會從這個記錄了一些被忽視的項目的小小的性能備忘錄裏得到一些提高。
1. 用ARC管理內存
ARC(AutomaticReference 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’sofficial 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 outthis article on eight myths about ARC to really convince you whyyou should be using it!
ARC固然不能爲你排除所有內存泄露的可能性。
由於堵塞,retain 週期, 管理不無缺的CoreFoundationobject(還有C結構)或者就是代碼太爛依舊能致使內存泄露。
這裏有一篇很是棒的介紹ARC不能作到以及咱們該怎麼作的文章http://conradstoll.com/blog/2013/1/19/blocks-operations-and-retain-cycles.html。
2. 在正確的地方使用 reuseIdentifier
一個開發中常見的錯誤就是沒有給UITableViewCells,UICollectionViewCells。甚至是UITableViewHeaderFooterViews設置正確的reuseIdentifier。
爲了性能最優化,tableview用 `tableView:cellForRowAtIndexPath:` 爲rows分配cells的時候。它的數據應該重用自UITableViewCell。一個tableview維持一個隊列的數據可重用的UITableViewCell對象。
不使用reuseIdentifier的話。每顯示一行tableview就不得不設置全新的cell。這對性能的影響可是至關大的,尤爲會使app的滾動體驗大打折扣。
自iOS6起。除了UICollectionView的cells和補充views,你也應該在header和footerviews中使用reuseIdentifiers。
想要使用reuseIdentifiers的話,在一個tableview中加入一個新的cell時在datasource object中加入這種方法:
1 2 |
staticNSString *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嵌在scrollview裏邊。或者是一個複雜動畫的一部分。不設置這個屬性的話會在很是大程度上影響app的性能。
你可以在模擬器中用Debug\ColorBlended Layers選項來發現哪些view沒有被設置爲opaque。目標就是。能設爲opaque的就全設爲opaque!
4. 避免過於龐大的XIB
iOS5中增長的Storyboards(分鏡)正在高速代替XIB。
然而XIB在一些場景中仍然很是實用。比方你的app需要適應iOS5以前的設備。或者你有一個本身定義的可重用的view,你就不可避免地要用到他們。
假設你不得不XIB的話。使他們儘可能簡單。嘗試爲每個Controller配置一個單獨的XIB,儘量把一個ViewController的view層次結構分散到單獨的XIB中去。
需要注意的是,當你載入一個XIB的時候所有內容都被放在了內存裏,包含不論什麼圖片。假設有一個不會即刻用到的view,你這就是在浪費寶貴的內存資源了。Storyboards就是還有一碼事兒了。storyboard僅在需要時實例化一個viewcontroller.
當家在XIB是,所有圖片都被chache,假設你在作OS X開發的話。聲音文件也是。Apple在相關文檔中的記述是:
當你載入一個引用了圖片或者聲音資源的nib時,nib載入代碼會把圖片和聲音文件寫進內存。
在OS X中,圖片和聲音資源被緩存在namedcache中以便未來用到時獲取。在iOS中。僅圖片資源會被存進namedcaches。取決於你所在的平臺。使用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 *)request queue:(NSOperationQueue*)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
或者使用像AFNetworking這種框架來異步地作這些操做。
假設你需要作其餘類型的需要耗費巨大資源的操做(比方時間敏感的計算或者存儲讀寫)那就用 GrandCentral 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 的細節感興趣的話,看看RayWenderlich的Multithreading and Grand Central Dispatch on iOS forBeginners。還有 SoheilAzarpour 的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很是快,使用valuelookup很是慢。插入/刪除很是慢。
· Dictionaries: 存儲鍵值對。
用鍵來查找比較快。
· Sets: 無序的一組值。用值來查找很是快。插入/刪除很是快。
8. 打開gzip壓縮
大量app依賴於遠端資源和第三方API,你可能會開發一個需要從遠端下載XML,JSON, HTML或者其餘格式的app。
問題是咱們的目標是移動設備。所以你就不能期望網絡情況有多好。一個用戶現在還在edge網絡,下一分鐘可能就切換到了3G。任何場景,你確定不想讓你的用戶等太長時間。
減少文檔的一個方式就是在服務端和你的app中打開gzip。
這對於文字這樣的能有更高壓縮率的數據來講會有更顯著的效用。
好消息是。iOS已經在NSURLConnection中默認支持了gzip壓縮,固然AFNetworking這些基於它的框架亦然。
像GoogleApp Engine這些雲服務提供者也已經支持了壓縮輸出。
假設你不知道怎樣利用Apache或者IIS(server)來打開gzip,可以讀下這篇文章。
中級性能提高
你確信你已經掌握了前述那些基礎級的優化方案了嗎?但實際狀況是,有時一些解決方式並不像那些同樣明顯,它們每每嚴重依賴於你怎樣架構和書寫你的app。如下的這些建議就是針對這些場景的。
9. 重用和延遲載入(lazy load) Views
不少其它的view意味着不少其它的渲染,也就是不少其它的CPU和內存消耗,對於那種嵌套了很是多view在UIScrollView裏邊的app更是如此。
這裏咱們用到的技巧就是模仿`UITableView`和`UICollectionView`的操做: 不要一次建立所有的subview。而是當需要時才建立,當它們完畢了使命。把他們放進一個可重用的隊列中。
這種話你就僅僅需要在滾動發生時建立你的views,避免了不划算的內存分配。
建立views的能效問題也適用於你app的其餘方面。
想象一下一個用戶點擊一個button的時候需要呈現一個view的場景。有兩種實現方法:
· 1. 建立並隱藏這個view當這個screen載入的時候。當需要時顯示它;
· 2. 當需要時才建立並展現。
每個方案都有其優缺點。
用第一種方案的話因爲你需要一開始就建立一個view並保持它直到再也不使用。這就會更加消耗內存。
然而這也會使你的app操做更敏感因爲當用戶點擊button的時候它僅僅需要改變一下這個view的可見性。
另一種方案則相反-消耗更少內存,但是會在點擊button的時候比第一種稍顯卡頓。
10. Cache, Cache, 仍是Cache!
一個極好的原則就是,緩存所需要的。也就是那些不大可能改變但是需要經常讀取的東西。
咱們能緩存些什麼呢?一些選項是。遠端server的響應,圖片,甚至計算結果。比方UITableView的行高。
NSURLConnection默認會緩存資源在內存或者存儲中依據它所載入的HTTPHeaders。你甚至可以手動建立一個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/*"forHTTPHeaderField:@"Accept"];
returnrequest; }
|
注意你可以經過NSURLConnection 獲取一個URL request。AFNetworking也同樣的。
這樣你就沒必要爲採用這條tip而改變所有的networking代碼了。
假設想了解不少其它關於HTTPcaching, NSURLCache, NSURLConnection的相關知識。可以讀下這篇文章()
假設你需要緩存其餘不是HTTPRequest的東西。你可以用NSCache。
NSCache和NSDictionary相似,不一樣的是系統回收內存的時候它會本身主動刪掉它的內容。
MatttThompson有一篇很是棒的關於它的文章::http://nshipster.com/nscache/
假設你對HTTP感興趣可以讀下Google的這篇best-practices document on HTTP caching。
11. 權衡渲染方法
在iOS中可以有很是多方法作出美麗的button。
你可以用整幅的圖片。可調大小的圖片。uozhe可以用CALayer,CoreGraphics甚至OpenGL來畫它們。
固然每個不一樣的解決方法都有不一樣的複雜程度和對應的性能。
有一篇AppleUIKit team中的一員Andy Matuschak推薦過的很是棒的關於graphic性能的帖子很是值得一讀。
簡單來講,就是用事先渲染好的圖片更快一些。因爲如此一來iOS就免去了建立一個圖片再畫東西上去而後顯示在屏幕上的程序。問題是你需要把所有你需要用到的圖片放到app的bundle裏面。這樣就添加了體積–這就是使用可變大小的圖片更好的地方了: 你可以省去一些沒必要要的空間。也不需要再爲不一樣的元素(比方button)來作不一樣的圖。
然而,使用圖片也意味着你失去了使用代碼調整圖片的機動性。你需要一遍又一遍不斷地重作他們,這樣就很是浪費時間了。而且你假設要作一個動畫效果,儘管每幅圖僅僅是一些細節的變化你就需要很是多的圖片形成bundle大小的不斷增大。
總得來講,你需要權衡一下利弊。到底是要性能能仍是要bundle保持合適的大小。
12. 處理內存警告
一旦系統內存太低,iOS會通知所有執行中app。在官方文檔中是這樣記述:
假設你的app收到了內存警告。它就需要儘量釋放不少其它的內存。最佳方式是移除對緩存。圖片object和其它一些可以重建立的objects的strongreferences.
幸運的是。UIKit提供了幾種收集低內存警告的方法:
· 在app delegate中使用`applicationDidReceiveMemoryWarning:`的方法
· 在你的本身定義UIViewController的子類(subclass)中覆蓋`didReceiveMemoryWarning`
· 註冊並接收UIApplicationDidReceiveMemoryWarningNotification 的通知
一旦收到這類通知,你就需要釋放不論什麼沒必要要的內存使用。
好比,UIViewController的默認行爲是移除一些不可見的view,它的一些子類則可以補充這種方法。刪掉一些額外的數據結構。一個有圖片緩存的app可以移除不在屏幕上顯示的圖片。
這樣對內存警報的處理是很是必要的。若不重視,你的app就可能被系統殺掉。
然而,當你必定要確認你所選擇的object是可以被重現建立的來釋放內存。
必定要在開發中用模擬器中的內存提醒模擬去測試一下。
13. 重用大開銷對象
一些objects的初始化很是慢,比方NSDateFormatter和NSCalendar。然而,你又不可避免地需要使用它們。比方從JSON或者XML中解析數據。
想要避免使用這個對象的瓶頸你就需要重用他們,可以經過加入屬性到你的class裏或者建立靜態變量來實現。
注意假設你要選擇另一種方法。對象會在你的app執行時一直存在於內存中,和單例(singleton)很是類似。
如下的代碼說明了使用一個屬性來延遲載入一個dateformatter. 第一次調用時它會建立一個新的實例,之後的調用則將返回已經建立的實例:
1 2 3 4 5 6 7 8 9 10 11 12 |
// in your .h or inside a class extension @property (nonatomic, strong) NSDateFormatter *formatter;
// inside the implementation (.m) // When you need, just use self.formatter - (NSDateFormatter *)formatter { if(! _formatter) { _formatter = [[NSDateFormatter alloc] init]; _formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";// twitter date format } return_formatter; }
|
還需要注意的是。事實上設置一個NSDateFormatter的速度差點兒相同是和建立新的同樣慢的!
因此假設你的app需要經常進行日期格式處理的話。你會從這種方法中獲得不小的性能提高。
14. 使用Sprite Sheets
你是一個遊戲開發人員嗎,那麼Spritesheets必定是一個你的最好的朋友了。Sprite sheet可以讓渲染速度加快。甚至比標準的屏幕渲染方法節省內存。
咱們有兩個很是好的關於Sprite的教程:
1 How To Use Animations and Sprite Sheets in Cocos2D
2 How to Create and Optimize Sprite Sheets in Cocos2D withTexture Packer and Pixel Formats
第二個教程涵蓋了可能在很是大程度上影響你遊戲性能的pixel格式的細節。
假設你對於spirtesheet還不是很是熟悉,可以看下這兩個(youtube)視頻SpriteSheets– TheMovie, Part 1和Part2。視頻的做者是建立Sprite sheet很是流行的工具之中的一個TexturePacker的做者Andreas Löw。
除了使用Spritesheets,其餘寫在這裏的建議固然也可以用於遊戲開發中。
比方你需要很是多的Spritesheets,像敵人,導彈之類的動做類必備元素。你可以重用這些sprites而不用每次都要又一次建立。
15. 避免重複處理數據
不少應用需要從server載入功能所需的常爲JSON或者XML格式的數據。在server端和client使用一樣的數據結構很是重要。在內存中操做數據使它們知足你的數據結構是開銷很是大的。
比方你需要數據來展現一個tableview,最好直接從server取array結構的數據以免額外的中間數據結構改變。
相似的,假設需要從特定key中取數據,那麼就使用鍵值對的dictionary。
16. 選擇正確的數據格式
從app和網絡服務間數據傳輸有很是多方案,最多見的就是JSON和XML。
你需要選擇對你的app來講最合適的一個。
解析JSON會比XML更快一些,JSON也一般更小更便於傳輸。
從iOS5起有了官方內建的JSON deserialization就更加方便使用了。
但是XML也有XML的優勢,比方使用SAX來解析XML就像解析本地文件同樣,你不需像解析json同樣等到整個文檔下載完畢才開始解析。當你處理很是大的數據的時候就會極大地減低內存消耗和添加性能。
17. 正確設定背景圖片
在View裏放背景圖片就像很是多其餘iOS編程同樣有很是多方法:
3 使用UIColor的colorWithPatternImage來設置背景色。
4 在view中加入一個UIImageView做爲一個子View。
假設你使用全畫幅的背景圖。你就必須使用UIImageView因爲UIColor的colorWithPatternImage是用來建立小的反覆的圖片做爲背景的。
這樣的情形下使用UIImageView可以節約很多的內存:
1 2 3 |
// You could also achieve the same result in Interface Builder UIImageView *backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background"]]; [self.view addSubview:backgroundView];
|
假設你用小圖平鋪來建立背景。你就需要用UIColor的colorWithPatternImage來作了,它會更快地渲染也不會花費很是多內存:
1 |
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background"]];
|
18. 下降使用Web特性
UIWebView很是實用,用它來展現網頁內容或者建立UIKit很是難作到的動畫效果是很是easy的一件事。
但是你可能有注意到UIWebView並不像驅動Safari的那麼快。這是由於以JIT compilation爲特點的Webkit的NitroEngine的限制。
因此想要更高的性能你就要調整下你的HTML了。第一件要作的事就是儘量移除沒必要要的javascript。避免使用過大的框架。
能僅僅用原生js就更好了。
另外。儘量異步載入好比用戶行爲統計script這樣的不影響頁面表達的javascript。
最後。永遠要注意你使用的圖片。保證圖片的符合你使用的大小。使用Spritesheet提升載入速度和節約內存。
不少其它相關信息可以看下WWDC2012 session #601 – Optimizing Web Content inUIWebViews and Websites on iOS
19. 設定Shadow Path
怎樣在一個View或者一個layer上加一個shadow呢,QuartzCore框架是很是多開發人員的選擇:
1 2 3 4 5 6 7 8 9 |
#import <QuartzCore/QuartzCore.h>
// Somewhere later ... UIView *view = [[UIView alloc] init];
// Setup the shadow ... view.layer.shadowOffset = CGSizeMake(-1.0f, 1.0f); view.layer.shadowRadius = 5.0f; view.layer.shadowOpacity = 0.6;
|
看起來很是easy,對吧。
可是,壞消息是使用這種方法也有它的問題… Core Animation不得不先在後臺得出你的圖形並加好陰影而後才渲染。這開銷是很是大的。
使用shadowPath的話就避免了這個問題:
view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];
使用shadowpath的話iOS就沒必要每次都計算怎樣渲染。它使用一個預先計算好的路徑。
但問題是本身計算path的話可能在某些View中比較困難,且每當view的frame變化的時候你都需要去updateshadow path.
想了解不少其它可以看看MarkPospesel的這篇。
20. 優化Table View
Tableview需要有很是好的滾動性能,否則用戶會在滾動過程當中發現動畫的瑕疵。
爲了保證tableview平滑滾動,確保你採取了下面的措施:
· 正確使用`reuseIdentifier`來重用cells
· 儘可能使所有的view opaque,包含cell自身
· 避免漸變。圖片縮放,後臺選人
· 緩存行高
· 假設cell內現實的內容來自web,使用異步載入,緩存請求結果
· 使用`shadowPath`來畫陰影
· 下降subviews的數量
· 儘可能不適用`cellForRowAtIndexPath:`。假設你需要用到它。僅僅用一次而後緩存結果
· 使用正確的數據結構來存儲數據
· 使用`rowHeight`, `sectionFooterHeight` 和`sectionHeaderHeight`來設定固定的高。不要請求delegate
21. 選擇正確的數據存儲選項
當存儲大塊數據時你會怎麼作?
你有很是多選擇。比方:
· 使用`NSUerDefaults`
· 使用XML, JSON, 或者 plist
· 使用NSCoding存檔
· 使用相似SQLite的本地SQL數據庫
· 使用 Core Data
NSUserDefaults的問題是什麼?儘管它很是nice也很是便捷。但是它僅僅適用於小數據,比方一些簡單的布爾型的設置選項,再大點你就要考慮其餘方式了
XML這樣的結構化檔案呢?總體來講,你需要讀取整個文件到內存裏去解析,這樣是很是不經濟的。
使用SAX又是一個很是麻煩的事情。
NSCoding?不幸的是,它也需要讀寫文件。因此也有以上問題。
在這樣的應用場景下,使用SQLite 或者 CoreData比較好。使用這些技術你用特定的查詢語句就能僅僅載入你需要的對象。
在性能層面來說。SQLite和CoreData是很是類似的。
他們的不一樣在於詳細用法。Core Data表明一個對象的graphmodel,但SQLite就是一個DBMS。
Apple在普通狀況下建議使用CoreData,但是假設你有理由不使用它,那麼就去使用更加底層的SQLite吧。
假設你使用SQLite,你可以用FMDB(https://GitHub.com/ccgus/fmdb)這個庫來簡化SQLite的操做,這樣你就不用花很是多經歷瞭解SQLite的C API了。
進階性能提示
想要一些是你成爲程序員忍者的精英級的建議嗎?如下這些提示可以幫你把你的app優化到極致!
22. 加速啓動時間
高速打開app是很是重要的,特別是用戶第一次打開它時,對app來說。第一印象太太過重要了。
你能作的就是使它儘量作不少其它的異步任務,比方載入遠端或者數據庫數據,解析數據。
仍是那句話。避免過於龐大的XIB。因爲他們是在主線程上載入的。
因此儘可能使用沒有這個問題的Storyboards吧。
注意,用Xcodedebug時watchdog並不執行。必定要把設備從Xcode斷開來測試啓動速度
23. 使用Autorelease Pool
`NSAutoreleasePool`負責釋放block中的autoreleasedobjects。
普通狀況下它會本身主動被UIKit調用。
但是有些情況下你也需要手動去建立它。
假如你建立很是多暫時對象。你會發現內存一直在下降直到這些對象被release的時候。
這是因爲僅僅有當UIKit用光了autoreleasepool的時候memory纔會被釋放。
好消息是你可以在你本身的@autoreleasepool裏建立暫時的對象來避免這個行爲:
1 2 3 4 5 6 7 8 9 |
NSArray *urls = <# An array of file URLs #>; for(NSURL *url in urls) { @autoreleasepool { NSError *error; NSString *fileContents = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error]; /* Process the string, creating and autoreleasing more objects. */ } }
|
這段代碼在每次遍歷後釋放所有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是一個好的方案。
SamSoffes有一個不錯的帖子(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性能的開發人員。
你首先需要保證你有使你的AppleID註冊爲一個開發人員身份才幹看在這裏看WWDC2012的視頻。
· #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 AnimationPerformance
· #601: Optimizing Web Content in UIWebViews andWebsites on iOS
· #225: Up and Running: Making a Great Impressionwith Every Launch
一些01年的WWDC視頻也很是有價值:
· #308: Blocks and Grand Central Dispatch inPractice
· #323: Introducing Automatic Reference Counting
· #312: iOS Performance and Power Optimizationwith Instruments
· #105: Polishing Your App: Tips and tricks toimprove the responsiveness and performance
· #121: Understanding UIKit Rendering
其餘一些值得看的視頻,大部分來自iOS 5Tech Talks:
· Your iOS App Performance Hitlist
· Optimizing App Performance with Instruments
· Understanding iOS View Compositing
基於《YouriOS App Performance Hitlist》這個Michael Jurewitz的視頻,OleBegemann寫了一篇文字總結的文章。
Apple提供了一個很實用的叫作「Performance Tuning | 性能調優」的資源。