增強iOS應用程序性能方法

1. ?使用ARC進行內(nèi)存管理

ARC除了能避免內(nèi)存泄露外,還有助于程序性能的提升

2.?在適當?shù)那闆r下使用reuseIdentifier

為了使用reuseIdentif iers,在tableview請求一個新的cell時,在數(shù)據(jù)源中調(diào)用下面的方法:

staticNSString*CellIdentifier=@"Cell";

UITableViewCell*cell=[tableViewdequeueReusableCellWithIdentifier:CellIdentifier f orIndexPat h:indexPat h];

3.?盡可能將View設置為不透明(Opaque)

opaque屬性提示繪制系統(tǒng)如何處理view。如果opaque設置為YES,繪圖系統(tǒng)會將view看為完全不透明,這樣繪圖系統(tǒng)就可以 優(yōu)化一些繪制操作以提升性能。如果設置為NO,那么繪圖系統(tǒng)結合其它內(nèi)容來處理view。默認情況下,這個屬性 是YES。

如果屏幕是靜止的,那么這個opaque屬性的設置與否不是一個大問題,但是,如果view是嵌入到scroll view中 的,或者是復雜動畫的一部分,不設置這個屬性的話肯定會影響程序的性能!

4.?避免臃腫的XIBs

如果必須要使用XIBs?的話,盡量讓XIBs?文件簡單。并且每個view controller對于一個XIB文件,如果可以的話,把一個view controller的view不同的層次單獨分到一個XIBs文件中。

當把一個XIB文件加載到內(nèi)存時,XIB文件中的所有內(nèi)容都 將被加載到內(nèi)存中,包括圖片。如果有一個view還不立即使用的 話,就會造成內(nèi)存的浪費。

5.?不要阻塞主線程

永遠都不要在主線程做繁重的任務。因為UIKit?的任務都在主線程中進 行,例如繪制、觸摸管理和輸入響應。如果你的代碼阻塞了主線程,那么程 序?qū)⒊霈F(xiàn)反應遲鈍。在執(zhí)行I/O操作中,大多數(shù)情況下都會阻塞主線程,這些操作需要從外部資源讀寫,例如磁盤或者網(wǎng)絡。

6.?讓圖片的大小跟UIImageView一樣

如果需要將程序bundle中的圖片顯示到UIImageView中,請確保圖 片和UIImageView的大小是一樣的。因為圖片的縮放非常耗費資 源,特別是將UIImageView嵌入到UIScro llView中。

如果是從遠程服務中下載圖片,有時候你控制不了圖片的尺寸, 或者在下載之前無法在服務器上進行圖片的縮放。這種情況,當 圖片下載完之后,你可以手動進行圖片的縮放,最好是在后臺線程中,然后再在UIImageView中使用縮放過的圖片。

7.?選擇正確的集合

數(shù)組:是一個值按順序排列的一個列表。根據(jù)索引可以快速查找,不過根據(jù)值進行查找就比較慢,另外插入和刪除也比較慢。

字典:?存儲鍵/值對。根據(jù)鍵可以快速查找。

Sets:?是一個值無序排列的列表,根據(jù)值可以快速查找,另外插入和刪除也比較快。

8.?使用GZIP壓縮

越來越多的程序依賴于外部數(shù)據(jù),這些數(shù)據(jù)一般來自遠程服務器或者其它的外部APIs?。使用GZIP對網(wǎng)絡傳輸中的數(shù)據(jù)進行壓縮,這樣可以減小文件的大小,并加快下載的速度。壓縮對于文本數(shù)據(jù)特別有用,因為文本具有很高的壓縮比。

9.?重用和延遲加載View

程序界面中包含更多的view,意味著界面在顯示的時候,需要進行更多的繪制任務,也就意味著需要消耗更多的CPU和內(nèi)存資源。特別是在一個UIScro llView里面加入了許多view。 這種情況的管理技巧可以參考UITableView和UICollectionView的行為:不要一次性創(chuàng)建所有的subview,而是在需要的時候在創(chuàng)建view,并且當view使用完畢時候?qū)⑺鼈兲砑拥街赜藐犃兄?。這樣就可以僅在UIScrollView滾動的時候才配置view,以此可以避免分配創(chuàng)建view帶來的成本。

現(xiàn)在有這樣的一個問題:在程序中需要顯示的view在什么時機創(chuàng)建(比如說,當用戶點擊某個按鈕,需要顯示某個view)。這里有兩種可選方法:

1.?在屏幕第一次加載以及隱藏的時候,創(chuàng)建view;然后在需要的時候,再把view顯示出來。

2.?直到需要顯示view的時候,才創(chuàng)建并顯示view。 每種方法都有各自的優(yōu)點和確定。

使用第一種方法,需要消耗更多的內(nèi)容,因為創(chuàng)建出來的view一直占據(jù)著內(nèi)存,直到view被release掉。不過,使用這種方法,當用戶點擊按鈕時,程序會很快的顯示出view,因為只需要修改一下view的可見性即可。

而使用第二種方法則產(chǎn)生相反的效果,當需要的時候才創(chuàng)建view,這會消耗更少的內(nèi)存,不過,當用戶點擊按鈕的時候,不會立即顯示出view。

10. 學會利用緩存

在開發(fā)程序時,一個重要的規(guī)則就是“緩存重要的內(nèi)容”——這些內(nèi)容一般不會改變,并且訪問的頻率比較高。遠程服務器的響應內(nèi)容,圖片,甚至是計算結果,比如UITableView的行高都可用緩存

11.?考慮繪制

在iOS中制作漂亮的按鈕有多種方法??梢允褂萌叽鐖D片,可縮放圖片,或者使用CALayer, CoreGraphics, 甚至是OpenGL來手 動測量和繪制按鈕。

使用預渲染圖片技術是最快的,因為iOS中不用等到在 屏幕上顯示的時候才創(chuàng)建圖形和對形狀進行繪制(圖片已經(jīng)創(chuàng)建 好了!)。這樣帶來的問題是需要把所有的圖片都放到程序bundle中,從而增加了程序的大小。

12.?處理內(nèi)存警告

當系統(tǒng)內(nèi)存偏低時,iOS會通知所有在運行的程序。

UIKit中提供了如下幾種方法來接收低內(nèi)存(low-memory)警告:

(1)實現(xiàn)app delegate中的applicationDidReceiveMemoryWarning:?方法。?

(2)在UIViewController子類中重寫(Override)didReceiveMemoryWarning方法。?

(3)在通知中心里面注冊UIApplicationDidReceiveMemoryWarningNotificatio通知。

在收到以上任意的警告時,需要立即釋放任何不需要的內(nèi)存。

例如,UIViewController的默認情況是清除掉當前不可見的view, 在UIViewController的子類中,可以清除一些額外的數(shù)據(jù)。程序中沒有顯示在當前屏幕中的圖片也可以release掉。

13.?重用花銷很大的對象

有些對象的初始化非常慢——比如NSDateFormatter和NSCalendar。不過有時候可以避免使用這些對象,例如在解析JSON/XML中的日期 時。當使用這些對象時,為了避免性能上的瓶頸,可以嘗試盡量重用這些 對象——在類中添加一個屬性或者創(chuàng)建一個靜態(tài)變量。

注意,如果使用靜態(tài)變量的話,對象會在程序運行的時候一直存在, 就像單例一樣

下面的代碼演示創(chuàng)建一個延遲加載的日期格式屬性。第一次調(diào)用屬性 的時候,會創(chuàng)建一個新的日期格式。之后再調(diào)用的話,會返回已經(jīng)創(chuàng) 建好的實例對象:

// in your .h or inside a class extension

@property (nonatomic, strong) NSDateFormatter *formatter;

//insidetheimplementation(.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的日期格式時,同樣跟創(chuàng)建新的一個NSDateFormatter實例對象 時一樣慢!因此, 在程序中如果需要頻繁的處理日期格式,那么對NSDateFormatter進行重用是非常好的。

14.?避免重新處理數(shù)據(jù)

許多程序都需要從遠程服務器中獲取數(shù)據(jù),以滿足程序的需求。這些數(shù)據(jù)一般是JSON或XML格式。在請求和接收數(shù)據(jù)時,使用相同的數(shù)據(jù)結構非常重要。為什么呢?在內(nèi)存中把數(shù)據(jù)轉(zhuǎn)換為適合程序的數(shù)據(jù)格式是需要付出額外代價的。

例如,如果你需要在tableview中顯示一些數(shù)據(jù),那么請求和接收的數(shù)據(jù)格式最好是數(shù)組格式的,這樣可以避免一 些中間操作——將數(shù)據(jù)轉(zhuǎn)換為適合程序使用的數(shù)據(jù)結構。

類似的,如果程序是根據(jù)鍵來訪問具體的值,那么最好請求和接收一個鍵/值對字典。

15.?選擇正確的數(shù)據(jù)格式

將數(shù)據(jù)從程序傳到網(wǎng)絡服務器中有多種方法,其中使用的數(shù)據(jù)格式基本都是JSON和XML。你需要做的就是在程序中選擇正確的數(shù)據(jù)格式。JSON的解析速度非常快,并且要比XML小得多,也就意味著只需要傳輸更少數(shù)據(jù)。

16.?設置適當?shù)谋尘皥D片

有兩種方法來給view設置一個背景圖片:

1.?可以使用UIColor的colorWithPatternImge方法來創(chuàng)建一個顏色,并將這個顏色設置為view的背景顏色。

2.?可以給view添加一個UIImageView子視圖。

如果你有一個全尺寸的背景圖片,那么應該使用UIImageView,因為UIColor的colorWithPatternImge方法是用來創(chuàng)建小圖片的——該圖片會被重復使用。此時使用UIImageView會節(jié)省很多內(nèi)存。

UIImageView*backgroundView=[[UIImageViewalloc]initWithImage:[UIImage imageNamed:@"background"]];

[self.view addSubview:backgroundView];

不過,如果你計劃用小圖片當做背景,那么應該使用UIColor的colorWithPatternImge方法。這種情況下繪制速度 會很快,并且不會消耗大量的內(nèi)存。

self.view.backgroundColor=[UIColorcolorWithPatternImage:[UIImage imageNamed:@"background"]];

17.?降低Web內(nèi)容的影響

UIWebView非常有用。用它可以很容易的顯示web內(nèi)容,甚至可以構建UIKit?空間難以顯示的內(nèi)容。不過,你可以能已經(jīng)注意到程序中使用的UIWebView組建沒有蘋果的Saf ari程序快。這是因為JIT?編譯限制了WebKit的Nitro引擎的使用。

因此為了獲得更好的性能,需要調(diào)整一下HTML的大小。首先就是盡量的擺脫JavaScript,并避免使用大的框架, 例如jQuery。有時候使用原始的JavaScript要比別的框架快。

另外,盡量的異步加載JavaScript文件——特別是不直接影響到頁面行為時,例如分析腳本。

最后——讓使用到的圖片,跟實際需要的一樣大小。以此節(jié)省內(nèi)存和提升速度。

18.?設置陰影路徑

如果需要在view活layer中添加一個陰影,該如何處理呢? 大多數(shù)開發(fā)者首先將QuartzCore框架添加到工程中,然后添加如下代碼:

1. #import <QuartzCore/QuartzCore.h> 2.

//Somewherelater...

UIView*view=[[UIViewalloc]init];

5.

// Setup the shadow ...

view.layer.shadowOffset = CGSizeMake(-1.0f, 1.0f);

view.layer.shadowRadius = 5.0f;

view.layer.shadowOpacity=0.6;

然而不幸的是上面這種方法有一個問題。Core Animation在渲染陰影效果之前,必須通過做一個離屏(of f screen)才能確定view的形狀,而這個離屏操作非常耗費資源。

下面有一種方法可以更容易的讓系統(tǒng)進行陰影渲染:設置陰影路徑!

view.layer.shadowPath=[[UIBezierPathbezierPathWithRect:view.bounds]CGPath];

通過設置陰影路徑,iOS就不用總是再計算該如何繪制陰影了。只需要使用你預先計算好的路徑即可。有一點不好的是,根據(jù)view的格式,自己可能很難計算出路徑。另外一個問題就是當view的frame改變時,必須每次都更新一下陰影路徑。

19.?優(yōu)化tableView

tableview需要快速的滾動——如果不能的話,用戶會感覺到停頓。

為了讓table view平滑的滾動,確保遵循了如下建議:

(1)設置正確的reuseIdentifer以重用cell。

(2) 盡量將view設置為不透明,包括cell本身。?

(3)避免漸變,圖像縮放以及離屏繪制。

(4)如果row的高度不相同,那么將其緩存下來。

(5) 如果cell顯示的內(nèi)容來自網(wǎng)絡,那么確保這些內(nèi)容是通過異步來獲取的。?

(6)使用shadowPath來設置陰影。

(7)減少subview的數(shù)量。?

(8)在cellForRowAtIndexPath:中盡量做更少的操作。如果需要做一些處理,那么最好做過一次之后,就將結果緩存起來。

(9)使用適當?shù)臄?shù)據(jù)結構來保存需要的信息。不同的結構會帶來不同的操作代價。

(10)使用rowHeight, sectionFooterHeight?和?sectionHeaderHeight?來設置一個恒定高度, ?而不要從delegate中獲取。

20.?選擇正確的數(shù)據(jù)存儲方式

當需要存儲和讀取大量的數(shù)據(jù)時,該如何選擇存儲方式呢? 有如下選擇:

?(1)使用NSUserDefaults進行存儲保存為XML

(2)JSON或Plist?格式的文件?

(3)利用NSCoding進行歸檔存儲到一個本地數(shù)據(jù)庫,例如SQLit e。?

(4)使用Core Data

雖然NSUserDef aults很好并且容易,不過只只針對于存儲小量數(shù)據(jù)

大量數(shù)據(jù)保存為結構化的文件也可能會帶來問題。一般,在解析這些結構數(shù)據(jù)之前,需要將內(nèi)容全部加載到內(nèi)存 中,這是很消耗資源的。雖然可以使用SAX來處理XML文件,但是這有點復雜。另外,加載到內(nèi)存中的所有對象, 不一定全部都需要用到。

那么使用NSCoding來保存大量數(shù)據(jù)怎么樣呢? 因為它同樣是對文件進行讀寫,因此依然存在上面說的問題。

要保存大量的數(shù)據(jù),最好使用SQLite或Core Data。通過SQLite或Core Data可以進行具體的查詢——只需要獲取

并加載需要的數(shù)據(jù)對象——避免對數(shù)據(jù)進行不合理的搜索。在性能方面,SQLite和Core Data差不大。

SQLite和Core Data最大的區(qū)別實際上就是用法上。Core Data代表一個對象模型,而SQLite只是一個DBMS。

一般,蘋果建議使用Core Data,不過如果你有特殊的原因不能使用Core Data的話,可以使用低級別的SQLite。

在程序中,如果選擇使用SQLite,這里有個方便的庫FMDB?:可以利用該庫操作SQLite數(shù)據(jù)庫,而不用深入使用SQLite C API。

21.?加速啟動時間

(1)讓程序盡量快速啟動的方法就是盡量以異步方式執(zhí)行任務,例如網(wǎng)絡請求,數(shù)據(jù)訪問或解析。

(2)另外,避免使用臃腫的XIBs,因為XIB的加載是在主線程中進行的。

22.?盡量避免Date格式化

如果有許多日期需要使用NSDateFormatter,那么需要小心對待了。如之前(重用花銷很大的對象)所提到的,

無論什么時候,都應該盡量重用NSDateFormatters。

然而,如果你需要更快的速度,那么應該使用C來直接解析日期,而不NSDateFormatter。Sam Sof fes寫了一 篇文章,其中提供了一些解析ISO- 8601格式日期字符的串代碼。你只需要簡單的調(diào)整一下其中的代碼就可以滿足自己特殊的需求了。

如果你自己能控制處理日期的格式,那么可以選擇?Unix timestamps。Unix timestamps是一個簡單的整數(shù),代表 了從新紀元時間(epoch)開始到現(xiàn)在已經(jīng)過了多少秒,通常這個新紀元參考時間是00:00:00 UTC on 1 January 1970。

你可以很容易的見這個時間戳轉(zhuǎn)換為NSDat e,如下所示:

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

? ? ? ? ? ret urn [NSDat e dat eWit hTimeInt ervalSince1970:t imest amp];

?}

上面這個方法比C函數(shù)還要快! 注意:許多網(wǎng)絡APIs返回的時間戳都是毫秒,因此需要注意的是在將這個時間戳傳遞給dateFromUnixTimestamp之前需要除以1000。

關于iOS 啟動性能優(yōu)化可參考:?https://mp.weixin.qq.com/s/Kf3EbDIUuf0aWVT-UCEmbA

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結構(3).初始化時...
    歐辰_OSR閱讀 30,260評論 8 265
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,667評論 1 32
  • 這是我的讀書會分享,我認為像是一堂課,也有自己的準備。 首先我克服了只說自己想講的內(nèi)容,去分析聽眾...
    潔楊閱讀 220評論 0 0
  • 所有發(fā)生過一次的事,可能永遠不會再發(fā)生;但所有發(fā)生過兩次的事,肯定還會發(fā)生第三次。 ——保羅·柯艾略 ???? 優(yōu)...
    angoal閱讀 224評論 0 0
  • 一 這是一本關于西方藝術史的書,按照時間順序介紹西方藝術(美術、雕塑、建筑)的發(fā)展歷程。1950年初版,其后每隔數(shù)...
    江火獨眠閱讀 3,491評論 0 7

友情鏈接更多精彩內(nèi)容