閱讀原文數據庫
在開發 iOS 應用程序時,確保應用程序具備良好的性能是相當重要的。然而,因爲開發週期的侷限性,讓咱們很容易忘記決策對性能的影響。這篇文章整理了一些提高性能的小技巧,但願會對你有所幫助。json
ARC 自動引用計數,會自動爲代碼在合適的位置添加ratain/release,你沒必要手動來管理它。這樣,就消除了最多見的內存泄漏問題。api
除了幫助你避免內存泄漏以外,ARC 還能夠經過確保對象在不在須要時當即釋放來提高性能。數組
值得注意的是,ARC 並不能消除全部的內存泄漏。即便使用 ARC ,仍可能會出現內存泄漏,這主要是因爲塊、引用循環、對 CoreFoundation 對象管理不善或糟糕的代碼引發的。緩存
在適當的地方使用重用標識,如:UITableViewCells、UICollectionViewCells、甚至是UITableViewHeaderFooterViews。bash
若是不使用重用標識,表視圖在每次顯示行的時,會配置一個一個全新的單元格,這是一個昂貴的操做,會影響滾動性能。服務器
在iOS 6以後,你也須要爲頁眉和頁腳視圖,以及 UICollectionView 的單元格和補充視圖使用重用標識。網絡
能夠經過將 opaque 屬性設置爲 YES 來設置,這個屬性默認是 YES。數據結構
該屬性會向繪圖系統提供有關如何處理視圖的提示。若是設置爲 YES , 繪圖系統會將視圖視爲徹底不透明,從而容許繪圖系統優化繪圖操做,從而提高性能。app
可使用 Debug\Color Blended Layers 選項來查看哪些視圖未設置爲不透明。
若是必需要使用 XIBs ,要儘量使它們簡單。當將xib加載到內存時,它全部的內容都會加載到內存中,包括圖像。若是你沒有當即使用它,那麼就會浪費寶貴的內存。
永遠不要在主線程上執行繁重的操做,由於 UIKit 在主線程上執行本身全部的工做,這樣會使頁面發生卡頓,嚴重影響用戶體驗。
大部分阻塞主線程的狀況發生在執行I/O操做時,由於該操做須要從外部資源(如:磁盤、網絡)讀取或寫入。
若是須要執行昂貴的操做,可使用 GCD 或 NSOperations 和 NSOperationQueues。
若是使用 UIImageView 來顯示圖像,要確保圖像和 UIImageView 的大小相同。動態縮放圖像會很是昂貴,特別是將 UIImageView 嵌入到 UIScrollView 中。
若是是從遠程服務器下載的圖像,有時可能沒法控制大小。那麼,能夠在圖像下載完成後,在後臺線程中手動縮放圖像,而後在 UIImageView中使用調整過大小的圖像。
學習使用最合適的類或對象來完成手頭的任務是編寫高效代碼的基礎。在處理集合時更是如此。一下時常見集合類型的簡要說明:
大部分應用程序都依賴於來自遠程服務器或其餘外部 api 的外部數據。在某個時候,您的應用程序,須要下載XML、JSON、HTML或其餘文本格式的數據。
問題是,當涉及到移動設備時,不能依賴網絡情況。用戶能夠在一分鐘內到達邊緣網絡,而後進入3G網絡。不論是什麼狀況,你都不想讓你的用戶等待!
減小文件大小和加快基於網絡的資源下載的一個選項是在服務器和客戶端上都啓用 gzip 壓縮。這對於基於文本的數據尤爲有用,由於它具備很高的潛在壓縮比。
更多的視圖意味着更多的繪製,這意味着更多的 CPU 和內存開銷。若是在 UIScrollView 中嵌入了不少視圖,這一點尤其重要。
管理它的技巧時模仿 UITableView 和 UICollectionView 的行爲:不要一次建立索引子視圖,而是根據須要建立視圖,並在完成時將其添加到重用隊列中。這樣,您只須要在執行滾動時配置視圖,從而避免分配成本—這可能會很昂貴。
建立視圖的時機至少有如下兩種方法:
這兩種方法各有利弊:
第一種方法會消耗更多的內存,由於會當即建立一個視圖,該視圖在釋放以前一直保留在內存中。可是,當須要顯示該視圖時,由於只須要更改視圖可見性,所以會更快顯示出視圖。
第二張方法會是相反的效果。只在須要時建立視圖,會消耗更少的內存。可是,在須要顯示時,視圖顯示不會那麼及時。
在開發應用程序時,一個很好的經驗法則是「緩存重要的東西」,也就是那些不太可能改變但常常訪問的東西。如:UITableViewCell 的行高,遠程服務器的響應等。
在 iOS 中,有幾種方法能夠製做漂亮的按鈕。可使用全尺寸圖像,可調整大小的圖像,也可使用 CALayer、CoreGraphics設置OpenGL手動繪製。
使用圖片會更快,由於沒必要建立圖像並在其上繪製形狀,就能夠最終顯示到屏幕上。問題是須要將這些圖片放入到項目中,會增長包大小。
考慮什麼對你最重要:繪製性能或包大小,而後選擇合適的方案。
當系統內存不足時,iOS 會通知全部正在運行的應用程序。若是你的應用收到此警告,它必須釋放盡量多的內存。最好的方式是:移除緩存,圖像對象,和稍後可從新建立的數據對象的強引用。
UIKit 提供了幾種接收低內存警告的方法:
一旦收到內存警告,釋放全部可能的內存是很是重要的。不然,您的應用程序可能會被系統殺死。
在開始剔除對象以釋放內存時要當心,由於須要確保之後能夠從新建立它們。在開發應用程序時,務必使用 iOS 模擬器上的模擬內存警告功能來測試此狀況。
有些對象的初始化速度很是慢,如 NSDateFormatter 和 NSCalendar 。可是,你不能老是避免使用它們,例如在解析 json/xml 響應中的日期。
爲了不在使用這些對象時出現性能瓶頸,要儘量重用這些對象。能夠經過向類中添加屬性或靜態變量來完成此操做。
注意,若是你選擇第二種方法,則當應用程序運行時,對象將保留在內存中,這與單例很是相似。
大部分應用程序都須要從遠程服務器獲取數據,這些數據一般以 json 或 xml 的格式出現。在請求和接收時,在兩端使用相同的數據結構是重要的。由於,操做內存中的數據以適應新的數據結構會是昂貴的。
例如,若是須要在表視圖中顯示數據,最好以數組格式請求和接收數據,以免對數據進行任何中間操做,使其適合你須要的數據結構。
相似地,若是應用程序依賴於經過鍵訪問特定值,那麼你須要請求並接收字典。
有多種方法能夠將數據從服務器傳輸到應用程序,但最多見的兩種方法是 JSON 和 XML 。你要確保爲你的應用選擇正確的一個。
JSON 的解析速度更快,並且一般比 xml 小,這也意味着傳輸更少的數據。並且自從 iOS 5以來,就有了內置的 JSON 反序列化,所以也很容易使用。
XML 的一個有點是,若是使用 SAX 解析方法,能夠在脫機狀態下使用 XML 數據,而沒必要等到整個數據到達後在像 JSON 那樣解析它。處理很是大的數據集時,這能夠提升性能並減小內存消耗。
至少有兩種方法能夠將背景圖像放置在視圖中:
若是您有一個全尺寸的背景圖像,那麼必定要使用 UIImageView ,由於 UIColor 的 colorWithPatternImage: 建立的是小圖,而不是大尺寸圖像。在這種狀況下,使用 UIImageView 將節省大量內存。
若是視圖背景使用較小的圖像,這些圖像將被重複或平鋪以填充背景,您應該使用 UIColor 的 colorWithPatternImage: 代替,由於在這種狀況下,繪製速度更快,並且不會佔用大量內存。
當要給視圖添加陰影時,大部分開發人員會向下面這樣:
UIView *view = [[UIView alloc] init];
view.layer.shadowOffset = CGSizeMake(-1.0f, 1.0f);
view.layer.shadowRadius = 5.0f;
view.layer.shadowOpacity = 0.6;
複製代碼
這種方法是有問題的, Core Animation必須進行一次離屏操做,以肯定視圖的確切形狀,而後才能渲染陰影,這個操做是很是昂貴的。
有一個系統更容易渲染的替代方案:設置陰影路徑。
view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];
複製代碼
經過設置陰影路徑,iOS 不須要從新計算它應該如何繪製陰影。相反,它會使用一個預先計算好的路徑。壞消息是,根據你的視圖樣式,可能很難由你本身計算路徑。另外一個問題是,每次視圖的幀發生更改時,都須要更新陰影路徑。
要使表視圖滾動順暢,確保實現如下建議:
在存儲和讀取大型數據時,會有以下選擇:
在保存的數據量很小的時候,可使用 NSUserDefaults 。
保存到結構化文件,須要先將整個文件加載到內存中,而後才能對其進行解析,這是一個昂貴的操做。你可使用 SAX 處理 XML 文件,這是一個複雜的解決方案。一樣,無論你想不想讓全部的對象都加載到內存中。
NSCoding 也須要讀取和寫入文件,會遇到和上面相同的問題。
最好使用 SQLite 或 Core Data。使用這些技術,您能夠執行特定的查詢以僅加載所需的對象,並避免使用暴力搜索方法來檢索數據。在性能方面,SQLite 和 Core Data 很是類似。
SQLite 和 Core Data 之間的最大區別在於它們的用法。Core Data表示一個對象圖模型,而 SQLite 只是一個普通的 DBMS。一般蘋果建議你使用 Core Data ,可是若是你有特殊的緣由想避免它,你可使用更底層的 SQLite 。
快速的啓動應用程序很是重要,尤爲當用戶第一次啓動時。第一印象對應用程序來講意義重大。
要使應用程序快速的啓動,能夠作的最大的事情是執行儘量多的異步任務,如網絡請求、數據庫訪問或解析數據。
另外,儘可能避免臃腫的 XIBs ,由於它是運行在主線程上的。
NSAutoreleasePool 負責釋放塊內的自動釋放對象。一般,它是由 UIKit 自動調用的。但在某些狀況下,可能須要手動建立 NSAutoreleasePools 。
若是在代碼中建立了許多臨時對象,則會注意到在釋放這些對象以前內存使用量會增長。問題是,只有在 UIKit 銷燬其自動釋放池以後,纔會釋放該內存,這意味着該內存的保存時間要比須要的長。
能夠經過在本身的@autoreleasepool塊中建立這些臨時對象來避免這種狀況。
加載 UIImage 有兩種常見的方法,第一種是使用 imageNamed , 第二種是使用 imageWithContentsOfFile 。
imageNamed 的優勢是在加載時緩存圖像。而 imageWithContentsOfFile 不會緩存。
若是要加載只使用一次的大圖像,則無需緩存該圖像。在這種狀況下,imageWithContentsOfFile 能夠很好地知足需求。這樣,操做系統就不會浪費內存來緩存圖像。
imageNamed 對於在應用程序中重用的圖像來講是一個更好的選擇。這樣,操做系統就節省了不斷從磁盤加載圖像的時間。
若是有不少日期須要用 NSDateFormatter 解析,須要當心處理。如前所述,儘量重用 NSDateFormatters 是一個好建議。
若是能夠控制要處理的日期的格式,請儘量選擇 Unix 時間戳。Unix 時間戳是簡單的整數。
關注公衆號:iOS學習社區,閱讀更多技術好文