概述
這里有25條進(jìn)行iOS應(yīng)用性能優(yōu)化的技巧,先列一下文檔的主要知識(shí)點(diǎn),分為基礎(chǔ),中級(jí)和高級(jí)是三個(gè)級(jí)別。
希望可以幫助到你。
原文地址放到最后了。
基礎(chǔ)
1、使用ARC管理內(nèi)存
2、使用reuseIdentifier進(jìn)行復(fù)用
3、盡可能把視圖設(shè)置為不透明
4、避免臃腫的XIB文件
5、不要阻塞主線程
6、調(diào)整圖像視圖中的圖片尺寸
7、選擇真確的集合
8、支持使用Gzip壓縮
中級(jí) ??在遇到復(fù)雜的情況使用
9、使用懶加載和復(fù)用方式加載視圖
10、使用緩存機(jī)制
11、對(duì)于繪圖的使用要多加考慮
12、處理內(nèi)存警告
13、針對(duì)占用內(nèi)存大的對(duì)象要進(jìn)行復(fù)用
14、使用精靈表
15、避免重復(fù)處理數(shù)據(jù)
16、選擇正確的數(shù)據(jù)格式
17、適當(dāng)?shù)脑O(shè)置背景圖片
18、減少網(wǎng)絡(luò)占用
19、設(shè)置陰影路徑
20、優(yōu)化表視圖
21、選擇正確的數(shù)據(jù)存儲(chǔ)類型
高級(jí) ??你覺得它們非常適用的時(shí)候使用
22、加速啟動(dòng)時(shí)間
23、使用自動(dòng)釋放池
24、緩存圖片
25、盡可能避免使用日期格式器
iOS開發(fā)的25條建議和技巧 - 基礎(chǔ)
1、使用ARC管理內(nèi)存
在iOS5之后就推出了ARC技術(shù),他是用來消除常見的內(nèi)存泄漏的技術(shù)。ARC自動(dòng)管理代碼中retain/release循環(huán)這樣就不用手動(dòng)管理這個(gè)事情了。
以下代碼是之前創(chuàng)建視圖的代碼
UIView *view = [[UIView alloc] init];
// ...
[self.view addSubview:view];
[view release];
這里經(jīng)常忘記release釋放,ARC會(huì)在后臺(tái)自動(dòng)幫你處理這個(gè)事情。
除了內(nèi)存釋放,ARC還能保證對(duì)象不在使用時(shí)立刻回收,從而提高APP的性能。
更多關(guān)于ARC的文檔:
Matthijs Hollemans’s Beginning ARC in iOS Tutorial
Tony Dahbura’s How To Enable ARC in a Cocos2D 2.X Project
-
如果你不確信ARC的好處,可以看一下這個(gè)文章 eight myths about ARC 。
??值得注意的是ARC不能消除所有的內(nèi)存泄漏。這里依然有內(nèi)存泄漏,這可能主要是由于blocks的循環(huán)引用,CoreFoundation管理對(duì)象的不善 或者是確實(shí)糟糕的代碼。
這里有個(gè)好的博客文章來說明怎么解決blocks循環(huán)引用問題—解決blocks循環(huán)引用地址
?
2、使用reuseIdentifier進(jìn)行復(fù)用
一個(gè)常見的錯(cuò)誤就是沒有給UITableViewCells,UICollectionViewCells,UITableViewHeaderFooterViews這些視圖設(shè)置復(fù)用標(biāo)識(shí)符。為最大優(yōu)化性能,一個(gè)tableview的數(shù)據(jù)源一般應(yīng)該復(fù)用UITableViewCell對(duì)象,當(dāng)它在tableView:cellForRowAtIndexPath:`方法給cells分配數(shù)據(jù)時(shí)。一個(gè)tableview維護(hù)了一個(gè)tableviewCell對(duì)象的隊(duì)列,這些對(duì)象都已經(jīng)被標(biāo)記上復(fù)用標(biāo)志。
如果不使用復(fù)用標(biāo)志,tableview 每次會(huì)創(chuàng)建一個(gè)新的cell。這是非常耗時(shí)的操作并且會(huì)影響到App滾動(dòng)的性能。
自動(dòng)iOS6之后,你應(yīng)該為header footer 視圖設(shè)置復(fù)用標(biāo)志,就像UICollectionView’s cells 和補(bǔ)充視圖一樣。
當(dāng)tableview提供一個(gè)新的cell時(shí)在這個(gè)方法中使用復(fù)用標(biāo)志。
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
如果隊(duì)列中有一個(gè)復(fù)用標(biāo)志的cell可以用,該方法會(huì)從隊(duì)列中取出來進(jìn)行復(fù)用。如果沒有就會(huì)從類或者XIB文件創(chuàng)建一個(gè)新的cell來使用。如果你的cell沒有使用復(fù)用標(biāo)志或者沒有從類或者xib文件注冊(cè)過,將會(huì)返回nil對(duì)象。
3、盡可能把視圖設(shè)置為不透明
如果沒有透明度的視圖你應(yīng)該將他們的opaque屬性為YES。這樣系統(tǒng)會(huì)以最優(yōu)的方式繪制你的視圖。你可以在Interface Builder或者代碼中設(shè)置這個(gè)屬性。
蘋果官方文檔也有對(duì)這個(gè)屬性的說明
這個(gè)屬性提供了一個(gè)暗示給系統(tǒng),該怎么對(duì)待這個(gè)視圖。如果設(shè)置為YES,系統(tǒng)在繪制這個(gè)視圖的時(shí)候?qū)⒆優(yōu)閺澢煌该鳎@樣會(huì)讓系統(tǒng)優(yōu)化一部分繪制操作并且提高APP性能。如果設(shè)置為NO,系統(tǒng)在繪制的時(shí)候會(huì)將這個(gè)視圖和其他內(nèi)容進(jìn)行復(fù)合。這個(gè)屬性默認(rèn)為YES。
在相對(duì)靜態(tài)的屏幕上設(shè)置opaque屬性不會(huì)有太大的問題。但是如果你的視圖嵌入scrollview或者復(fù)雜的動(dòng)畫,再不設(shè)置這個(gè)屬性的情況下你的應(yīng)用絕對(duì)會(huì)收到影響。
在模擬器情況下,你可以使用Debug\Color Blended Layers選項(xiàng)來觀察視圖有沒有設(shè)置不透明。你應(yīng)該盡可能設(shè)置更多的不透明視圖。
4、避免臃腫的XIB文件
在iOS5之后引入了故事板Storyboards很快就代替了XIBs。但是 XIBS在一定情況下還是很有用的。如果你需要支持iOS5之前的設(shè)備或者你想自定義復(fù)用的視圖,那么你不可能避免使用它。
??當(dāng)你加載一個(gè)XIB視圖進(jìn)入內(nèi)存時(shí),xib上面包含的所有內(nèi)容包括圖片在內(nèi)都會(huì)加載到內(nèi)存中去。
如果你有一個(gè)不立即使用的視圖,那么你就浪費(fèi)了寶貴的內(nèi)存。??這個(gè)事情不會(huì)發(fā)生在故事板上,因?yàn)橐粋€(gè)故事只能在需要的時(shí)候?qū)嵗粋€(gè)視圖控制器。
當(dāng)你加載一個(gè)XIB時(shí),包括圖片在內(nèi)的所有文件都會(huì)被緩存下來,如果是開發(fā)OS X 那么音頻文件也會(huì)被緩存下來。官方文檔如下:
When you load a nib file that contains references to image or sound resources, the nib-loading code reads the actual image or sound file into memory and and caches it. In OS X, image and sound resources are stored in named caches so that you can access them later if needed. In iOS, only image resources are stored in named caches. To access images, you use the imageNamed: method of NSImage or UIImage, depending on your platform.
5、不要阻塞主線程
你永遠(yuǎn)不能在主線程處理任何繁重的工作。這是因?yàn)閁IKit的所有工作都在主線程中進(jìn)行,例如繪圖,管理觸摸和響應(yīng)輸出。
應(yīng)用中所有的工作都在主線程中處理就會(huì)有導(dǎo)致主線程阻塞,應(yīng)用反應(yīng)遲鈍的風(fēng)險(xiǎn)。
大部分阻塞主線程的情況發(fā)生在應(yīng)用進(jìn)行I/O操作。包括任何需要讀寫外部資源任務(wù),比如磁盤讀寫和網(wǎng)絡(luò)請(qǐng)求。
你使用下面的方法進(jìn)行網(wǎng)絡(luò)的異步請(qǐng)求或者AFNetwoking 第三方庫請(qǐng)求
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler</pre>
如果你需要做大量的開銷操作,例如執(zhí)行耗時(shí)的計(jì)算或者磁盤的讀寫,你可以使用GCD或者隊(duì)列來操作。
GCD使用舉例如下:
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
//所有的UIKit的操作都需要在主線程處理,所有這里使用dispatch_async
});
});
6、調(diào)整圖像視圖中的圖片尺寸
如果你使用UIImageView加載應(yīng)用中的圖片,你要確保圖片的大小和UIImageView視圖的大小一致。縮放圖片是非常耗時(shí)的,特別是在UIImageView被嵌套在UIScrollView的時(shí)候。
如果圖片是從服務(wù)器下載的,你沒有辦法控制圖片大小或者你不能在下載之前縮放圖片。這些情況,你可以在圖片下載完成之后進(jìn)行手動(dòng)縮放一次,最好放到后臺(tái)進(jìn)程進(jìn)行處理,然后在將適應(yīng)的圖片放到UIImageView中。
7、選擇真確的集合
學(xué)著選擇最合適的類和對(duì)象,寫出高效的代碼。當(dāng)使用集合collections時(shí)最恰當(dāng)不過了
值得高興的是,蘋果開發(fā)者文檔有詳細(xì)的文檔解釋可用類之間的關(guān)系,還有各個(gè)類適用的情況。這個(gè)文檔是每個(gè)人必須的文檔。
這是一個(gè)常見的集合類型的快速簡介
Arrays:有序值的列表,用index進(jìn)行查找最快,使用值查找慢,插入和刪除操作比較慢。
Dictionaries:保存 鍵/值對(duì)。使用key查找最快。
Sets:無序的值列表??焖俨檎沂褂弥挡檎遥迦牒蛣h除操作比較快。
8、支持使用Gzip壓縮
應(yīng)用中大部分?jǐn)?shù)據(jù)都依賴于服務(wù)端或者外部接口。有時(shí)應(yīng)用中需要下載XML,JSON,HTML或者其他數(shù)據(jù)。
問題是,當(dāng)涉及到移動(dòng)設(shè)備時(shí),網(wǎng)絡(luò)條件是不可依賴的。用戶可以在一分鐘的邊緣網(wǎng)絡(luò),下一個(gè)3G網(wǎng)絡(luò)。不管發(fā)生什么情況,您都不想讓用戶等待。
一個(gè)減小文件大小和加速下載網(wǎng)絡(luò)資源的方法是在你的服務(wù)器端和客戶端使用GZIP壓縮。對(duì)于文本數(shù)據(jù)來說這種高比率壓縮的方法非常有效。
好消息是iOS已經(jīng)支持GZIP壓縮,如果你在使用NSURLConnection或者類似AFNetworking的第三方庫。而且一切云服務(wù)提供商比如Google App Engine早已經(jīng)發(fā)送壓縮后的數(shù)據(jù)。
這篇文章介紹怎樣在Apache或者IIS服務(wù)器上啟動(dòng)GZIP。
iOS開發(fā)的25條建議和技巧 - 中級(jí)
現(xiàn)在你已經(jīng)了解了基礎(chǔ)的方法來優(yōu)化性能,但是問題的解決方法并不是那么顯而易見,它由你的APP框架和代碼的質(zhì)量決定。下面看一下中級(jí)優(yōu)化方案。
9、使用懶加載和復(fù)用方式加載視圖
更多的視圖意味著更多的繪制,最終意味著CPU和內(nèi)存的開銷。如果你的視圖中包含很多UIScrollView時(shí),這會(huì)顯得非常正確。
管理這樣的視圖的技巧是:不要一次性的創(chuàng)建所有的子視圖,而是在需要的時(shí)候去創(chuàng)建,然后把它們放入到復(fù)用的隊(duì)列中。
用這種方法,你只需要在視圖需要的時(shí)候配置你的視圖,避免了資源的分配開銷。
視圖創(chuàng)建的時(shí)機(jī)同樣也適用于APP的其他地方。猜想一個(gè)按鈕點(diǎn)擊的時(shí)候需要呈現(xiàn)一個(gè)視圖,這里至少有兩種情況。
當(dāng)屏幕上第一次載入的時(shí)候創(chuàng)建并隱藏視圖。當(dāng)你需要的時(shí)候去創(chuàng)建并展示出來。
當(dāng)需要展示的情況下創(chuàng)建視圖并展示它。
每種方式都有它的優(yōu)缺點(diǎn)。
第一個(gè)方法,你占用了更多的內(nèi)存,因?yàn)閺膭?chuàng)建開始到釋放你都保持了他的內(nèi)存。然而你在點(diǎn)擊按鈕的時(shí)候你的應(yīng)用可以快速的改變狀態(tài),展示不同的視圖。
第二個(gè)方法確實(shí)消耗了更少的內(nèi)存,但是當(dāng)點(diǎn)擊按鈕時(shí)響應(yīng)并不像第一種方法那么迅速。
10、使用緩存機(jī)制
那些經(jīng)常被訪問但是不經(jīng)常改變的東西在開發(fā)過程中應(yīng)該被緩存下來。
你能緩存什么內(nèi)容?緩存遠(yuǎn)程服務(wù)器的響應(yīng),圖片或者計(jì)算值(UITableView的行高)。
NSURLConnection可以根據(jù)HTTP頭信息緩存資源到內(nèi)存或者磁盤中去。你甚至可以創(chuàng)建一個(gè)NSURLRequest值加載緩存過的值。
下面是你需要針對(duì)一個(gè)不會(huì)改變的圖片創(chuàng)建的一個(gè)NSURLRequest
+ (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"];
return request;
}
你可以在NSHiper上了解到更多關(guān)于HTTP caching,NSURLCache,NSURLConnection等內(nèi)容。
如果你需要緩不涉及到HTTP請(qǐng)求的其他東西,NSCache 是個(gè)很好的選擇。
NSCache和NSDictionary比較像,但是當(dāng)系統(tǒng)需要回收內(nèi)存的時(shí)候,他會(huì)自動(dòng)移除內(nèi)容。
關(guān)于HTTP caching 可以看一下這個(gè)文章
11、對(duì)于繪圖的使用要多加考慮
在iOS中你可以制作很多好看的按鈕。你可以直接使用圖片或者使用CALayer甚至OpenGL進(jìn)行繪制。
當(dāng)然,每種方法都有不同的復(fù)雜級(jí)別和性能差別。這篇文章會(huì)有幫助 幫助了解對(duì)性能的權(quán)衡。
使用預(yù)渲染圖片會(huì)更快,因?yàn)閕OS不用創(chuàng)建一張圖片和繪制圖形到屏幕上。你需要把所有圖片都放入到應(yīng)用的bundle中,增加它的尺寸。為什么使用可調(diào)整尺寸的圖片那么好:你通過移除不用的圖片來節(jié)省空間。您不需要為不同的元素生成不同的圖像。
然而,用圖片你會(huì)失去代碼調(diào)整你圖片的能力,需要每次生成并把它們加入到應(yīng)用中。這是個(gè)緩慢的過程。還有一點(diǎn)是,如果你使用動(dòng)畫或者多張圖片,你需要加載大量的圖片,這樣會(huì)導(dǎo)致應(yīng)用的大小。
總結(jié)一下,你需要考慮一下哪個(gè)更重要:繪制性能還是應(yīng)用的大小。當(dāng)然兩個(gè)都很重要,兩種方法你都要使用。
12、處理內(nèi)存警告
當(dāng)系統(tǒng)內(nèi)存低時(shí),系統(tǒng)會(huì)通知所有運(yùn)行的應(yīng)用。官方關(guān)于低內(nèi)存的描述
如果你的應(yīng)用接收到低內(nèi)存的警告,它必須釋放盡可能多的內(nèi)存。最好的方式是移除那些緩存,圖片和其他稍后要?jiǎng)?chuàng)建的對(duì)象的強(qiáng)引用。
幸運(yùn)的是,UIKit提供了一些方法來接受處理低內(nèi)存警告
- Implement the applicationDidReceiveMemoryWarning: method of your app delegate.
- Override didReceiveMemoryWarning in your custom UIViewController subclass.
- Register to receive the UIApplicationDidReceiveMemoryWarningNotification notification.
當(dāng)上面任何一個(gè)接收到內(nèi)存警告,你需要及時(shí)釋放掉那些不必要的內(nèi)存。
例如當(dāng)前控制器上的視圖不可見,控制器會(huì)清除這些視圖。子類可以通過父類方法來清除額外的數(shù)據(jù)。一個(gè)應(yīng)用的中任何沒有在屏幕上的圖片的緩存都會(huì)被釋放掉。
及時(shí)的釋放掉內(nèi)存非常重要,否則應(yīng)用就可能被系統(tǒng)殺死。
你需要小心的釋放內(nèi)存,因?yàn)槟阈枰WC他們會(huì)在之后被重新創(chuàng)建。當(dāng)你開發(fā)應(yīng)用的時(shí)候,用你的模擬器去測(cè)試內(nèi)存警告這種情況。
13、針對(duì)占用內(nèi)存大的對(duì)象要進(jìn)行復(fù)用
有些對(duì)象創(chuàng)建過程非常慢-NSDateFormatter和NSCalendar就是例子。
為了避免使用這些對(duì)象時(shí)的性能瓶頸,試著重用這些對(duì)象。你可以把它設(shè)置為一個(gè)類的屬性或者一個(gè)靜態(tài)變量。
??如果你用第二種方法,這個(gè)對(duì)象會(huì)在APP運(yùn)行時(shí)一直保持在內(nèi)存中,像一個(gè)單例一樣。
下面演示了一個(gè)NSDateFormatter作為一個(gè)屬性的懶加載方法,第一次調(diào)用創(chuàng)建,以后使用都使用創(chuàng)建的這一個(gè)對(duì)象。
// 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;
}
如果在多個(gè)線程調(diào)用這個(gè)方法就會(huì)出現(xiàn)問題,所以針對(duì)這個(gè)多線程的問題我們使用下面的定義方法來定義NSDateFormatter。
// no property is required anymore. The following code goes inside the implementation (.m)
?
- (NSDateFormatter *)formatter {
static NSDateFormatter *formatter;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_formatter = [[NSDateFormatter alloc] init];
_formatter.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy"; // twitter date format
});
return formatter;
}
設(shè)置一個(gè)NSDateFormatter 的日期格式幾乎和創(chuàng)建一個(gè)新的一樣慢。因此當(dāng)你的應(yīng)用中要處理多個(gè)日期格式時(shí)使用復(fù)用和初始化創(chuàng)建會(huì)更加有利。
14、使用精靈表 (游戲開發(fā)者??)
如果你是游戲開發(fā)者。精靈表是你的好朋友之一。精靈表比標(biāo)準(zhǔn)屏幕繪制的速度更加快速。
下面有兩個(gè)是喲哦那個(gè)精靈表的使用教程:
第二個(gè)教程覆蓋了像素格式,他可能對(duì)游戲性能有一個(gè)可衡量的影響。
如果你不是很熟悉精靈表,這有個(gè)教程詳細(xì)介紹了這個(gè)精靈表- SpriteSheets – The Movie, Part 1 and Part 2.
除了精靈表之外,之前說的內(nèi)容也可以用到游戲開發(fā)上面。舉例:如果你的游戲中有很多精靈,比如在標(biāo)準(zhǔn)的敵人或者炮彈射擊游戲,你可以重用精靈表來代替每次創(chuàng)建新的精靈。
15、避免重復(fù)處理數(shù)據(jù)
許多APP調(diào)用函數(shù)來獲取服務(wù)器數(shù)據(jù)。數(shù)據(jù)格式一般都是JSON或者XML格式。保持統(tǒng)一的數(shù)據(jù)格式對(duì)于請(qǐng)求和接收數(shù)據(jù)來說非常重要。
為什么?處理內(nèi)存中的數(shù)據(jù)以適合您的數(shù)據(jù)結(jié)構(gòu)可能是昂貴的。
例如:你需要在表格中展示數(shù)據(jù)。最好的請(qǐng)求和接收數(shù)據(jù)的格式時(shí)數(shù)組,以避免中間操作數(shù)據(jù)。
相似的,如果你的影喲ing依賴于訪問特定的鍵值,你會(huì)更加希望返回的數(shù)據(jù)格式是一個(gè)字典格式。
通過一次性獲取正確的數(shù)據(jù)格式,你會(huì)避免許多重復(fù)處理數(shù)據(jù)的工作。
16、選擇正確的數(shù)據(jù)格式
這里有許多方式你可以從web服務(wù)器獲取數(shù)據(jù)傳遞到你的應(yīng)用中。到那時(shí)最常見的是JSON和XML格式,你要選擇正確的格式來適應(yīng)你的應(yīng)用。
JSON比XML轉(zhuǎn)化更加快,傳輸內(nèi)容也比較小。自從iOS5之后,內(nèi)置的JSON解析很簡單也很實(shí)用。
然而,XML在你使用SAX parsing方法時(shí)是有優(yōu)勢(shì)的。你可以在傳輸過程中讀取它,在數(shù)據(jù)量非常大時(shí),你可以不必像JSON一樣在下載完成后在去處理。
17、適當(dāng)?shù)脑O(shè)置背景圖片
這里有兩種加載替換背景圖片的方法。
通過使用UIColor 的
colorWithPatternImage方法設(shè)置視圖的背景顏色-
在視圖上添加一個(gè)
UIImageView視圖如果你有一個(gè)全尺寸的背景圖片,你應(yīng)該使用
UIImageView視圖。因?yàn)?code>colorWithPatternImage這個(gè)方法是重復(fù)創(chuàng)建小的模型圖片。在這種情況下使用UIImageView會(huì)節(jié)省很多內(nèi)存。
// You could also achieve the same result in Interface Builder
UIImageView *backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background"]];
[self.view addSubview:backgroundView];</pre>
如果你想使用小的圖片作為背景,你可以使用colorWithPatternImage這種哦方式,在這種情況下不會(huì)使用太多內(nèi)存。
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background"]];</pre>
18、減少網(wǎng)絡(luò)占用
UIWebView是非常有用的。他可以輕松的展示網(wǎng)站內(nèi)容,或者創(chuàng)建你的app窗體。這些都是UIKit很難做到的。
但是,你可能注意到UIWebView組件并沒有像蘋果的safari應(yīng)用那么快。這是因?yàn)閃ebKit引擎的限制,以JIT編譯。
所以 獲取更佳的體驗(yàn)?zāi)阈枰薷哪愕腍TML。第一件事是盡可能的避免使用Javascript,包括避免使用大的框架例如jQuery。有時(shí)使用vanilla Javascript取代依賴的框架會(huì)更快
還要遵循在可能的情況下異步加載JavaScript文件,尤其是當(dāng)它們不直接影響頁面的行為時(shí),比如分析腳本。
最后,要使用正確的圖片尺寸。正如上面說到的使用精靈表的優(yōu)勢(shì)來節(jié)省內(nèi)存。
And finally — always be aware of the images that you are using, and keep images right-sized for your purposes. As mentioned earlier in this tutorial, make use of sprite sheets wherever possible to conserve memory and improve speed.
更多信息可以看這個(gè)地址-> WWDC 2012 session #601 – Optimizing Web Content in UIWebViews and Websites on iOS.
19、設(shè)置陰影路徑
你要給視圖添加陰影怎么處理?
大多數(shù)開發(fā)者會(huì)使用QuartzCore框架添加如下代碼:
#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;</pre>
看起來很簡單,對(duì)嗎?
不好的是這個(gè)方法有一個(gè)問題。Core Animation-核心動(dòng)畫必須先做一個(gè)幕后畫確定視圖的形狀之后才渲染陰影,這是一個(gè)相當(dāng)費(fèi)事而且昂貴的操作。
好消息是這個(gè)有個(gè)更簡單的替換方法設(shè)置陰影路徑:
view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];
設(shè)置陰影路徑,iOS不需要一直計(jì)算如何繪制陰影。但是它會(huì)依賴你的視圖格式,你的視圖更加難以計(jì)算。還有一個(gè)問題是當(dāng)視圖坐標(biāo)改變時(shí)你需要更新陰影路徑。
你可以獲取更多的關(guān)于這個(gè)內(nèi)容的技巧-> post about shadowPath.
20、優(yōu)化表視圖
表格視圖需要支持快速滾動(dòng),如果不行,用戶會(huì)感覺太low了。
為了保持表格滾動(dòng)的流暢,你可以使用以下建議:
使用
reuseIdentifier-復(fù)用標(biāo)志進(jìn)行單元格的復(fù)用保證視圖設(shè)置為不透明,包括單元格自己
避免漸變,圖片縮放和屏幕外的繪制
當(dāng)單元格高度不一致時(shí)緩存單元格高度
如果單元格展示的內(nèi)容來自web,確保異步請(qǐng)求并緩存
使用
shadowPath設(shè)置陰影減少子視圖
cellForRowAtIndexPath方法中盡可能少的做事情。如果必須要處理,盡量一次性處理并緩存結(jié)果使用適當(dāng)?shù)臄?shù)據(jù)結(jié)構(gòu)存儲(chǔ)你要的信息。不同的結(jié)構(gòu)對(duì)于不同的操作有不同的代價(jià)
設(shè)置
rowHeightsectionFooterHeightsectionHeaderHeight為固定高度而不是訪問代理方法
21、選擇正確的數(shù)據(jù)存儲(chǔ)類型
存儲(chǔ)和讀取數(shù)據(jù)的時(shí)候選擇什么?有以下幾種選擇:
使用NSUserDefaults存儲(chǔ)
使用XML,JSON或者plist格式的文件
使用NSCoding歸檔文件
使用SQLLite保存到數(shù)據(jù)庫中
使用Core Data數(shù)據(jù)庫存儲(chǔ)
NSUserDefaults有什么問題?雖然NSUserDefaults很簡單也很好用,但是它只適合存儲(chǔ)少量的數(shù)據(jù)。如果存儲(chǔ)大量的數(shù)據(jù)其他方式會(huì)更好。
保存在文件也可能有問題。一般來說在處理數(shù)據(jù)之前你需要加載整個(gè)文件到內(nèi)存中,這個(gè)時(shí)非常耗時(shí)的操作。你可以使用SAX去處理XML文件,但是也是一個(gè)復(fù)雜的做法。加載全部對(duì)象到內(nèi)存中,這也不是你想看到的。
那么NSCoding怎樣呢?很不幸運(yùn),他在讀取和寫入文件時(shí)也會(huì)出現(xiàn)同樣的問題。
處理這個(gè)問題的最好方式是使用SQLLite或者Core Data 。使用這些技術(shù),你可以執(zhí)行特定的查詢來加載需要的對(duì)象,避免了強(qiáng)力搜索方法來檢索數(shù)據(jù)。SQLite和Core Data性能方面很接近。
SQLLite和Core Data最大的不同是他們的使用方法。CoreData呈現(xiàn)為一個(gè)模型,但是SQLite確是一個(gè)傳統(tǒng)的DBMS 數(shù)據(jù)庫管理系統(tǒng)。蘋果建議使用Core Data,如果你有特殊原因你想避開CoreData,你可以使用哦更低級(jí)的SQLLite。
在APP中使用SQLLite,你要引入FMDB庫。它允許你使用SQLLite而不用專研SQLLite的 C API。
iOS開發(fā)的25條建議和技巧 - 高級(jí)
下面這些方法會(huì)讓你的應(yīng)用更加的高效。
22、加速啟動(dòng)時(shí)間
快速啟動(dòng)對(duì)于應(yīng)用來說非常重要,特別是當(dāng)用戶第一次啟動(dòng)應(yīng)用的時(shí)候。
盡最大的努力保證APP啟動(dòng)更加快,盡可能執(zhí)行異步任務(wù),例如網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)庫訪問,數(shù)據(jù)解析。
避免使用臃腫的XIB,因?yàn)樗鼈儠?huì)在主線程中加載 。但是故事板不會(huì)有這個(gè)問題。
??當(dāng)Xcode運(yùn)行調(diào)試時(shí)看門狗不會(huì)運(yùn)行,所以一定要與你的設(shè)備斷開Xcode而測(cè)試你的應(yīng)用程序。
23、使用自動(dòng)釋放池
NSAutoreleasePool負(fù)責(zé)釋放在block塊中的自動(dòng)釋放的對(duì)象。一般情況,它是由UIKit自動(dòng)調(diào)用。但是有些情景你需要手動(dòng)創(chuàng)建NSAutoreleasePools。
比如,你在代碼中創(chuàng)建了大量的臨時(shí)對(duì)象,你會(huì)注意到內(nèi)存會(huì)一直增加直到這些對(duì)象被釋放。這個(gè)問題在于內(nèi)存釋放只有在UIKit排空自動(dòng)釋放池的時(shí)候才會(huì)釋放內(nèi)存,這就意味著內(nèi)存會(huì)被占用的時(shí)間超過了需要的時(shí)間。
問題是,這種是UIKit耗盡后自動(dòng)釋放池才發(fā)布,這意味著這種記憶保持更長的時(shí)間比必要的。
你可在autoreleasepool中創(chuàng)建臨時(shí)對(duì)象來避免這種情況,如下:
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. */
}
}
在每次迭代之后會(huì)自動(dòng)釋放這些對(duì)象。
更多關(guān)于 *NSAutoreleasePool看這里- > Apple’s official documentation.
24、緩存圖片
這里有兩種從bundle加載圖片到應(yīng)用的方法。第一種是使用imageNamed。第二種是使用imageWithContentsOfFile 方法。
為什么兩種方法處理同一個(gè)事情呢,哪個(gè)更高效呢?
imageNamed在載入圖片之后會(huì)將圖片緩存到內(nèi)存中。官方文檔解釋如下:
這個(gè)方法看起來在系統(tǒng)緩存一個(gè)圖片并指定一個(gè)名字,如果存在則返回一個(gè)對(duì)象。如果不存在會(huì)從指定文件中加載這個(gè)圖片并緩存它,然后返回結(jié)果對(duì)象。
imageWithContentsOfFile只是簡單的加載圖片并不緩存。
兩種方法的使用方法如下:
UIImage *img = [UIImage imageNamed:@"myImage"]; // caching
// or
UIImage *img = [UIImage imageWithContentsOfFile:@"myImage"]; // no caching</pre>
在什么情況使用哪個(gè)方法?
如果你加載一張大的圖片但是只加載一次的時(shí)候,并且不需要緩存圖片。這種情況下使用imageWithContentsOfFile。這樣就不會(huì)浪費(fèi)內(nèi)存來緩存圖片了。
然而imageNamed對(duì)于圖片加載來說會(huì)是更好的選擇。這種方法會(huì)節(jié)省從磁盤加載圖片的時(shí)間。
25、盡可能避免使用日期格式器
如果你有大量的數(shù)據(jù)需要轉(zhuǎn)化為日期格式,這時(shí)你就要注意了。之前提過,盡可能復(fù)用NSDateFormatters。
然而,你需要更加快速,你可以使用C來代替NSDateFormatter來解析數(shù)據(jù)。這篇文章-> blog post about this topic說明了如何使用代碼來解析ISO-8601數(shù)據(jù)格式的字符串。你可以根據(jù)你的需求快速地更改demo代碼。
這個(gè)聽起來很棒,但是你相信有更好的辦法嗎?
如果你能控制你要處理的日期數(shù)據(jù)格式,盡可能選用 Unix timestamps。Unix時(shí)間戳可以簡單的整數(shù)代表從某個(gè)起點(diǎn)到現(xiàn)在的秒殺。這個(gè)起點(diǎn)默認(rèn)是1970年1月1日 UTC 00:00:00
你可以很容易把時(shí)間戳轉(zhuǎn)化為NSDATE,如下:
- (NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {
return [NSDate dateWithTimeIntervalSince1970:timestamp];
}
這個(gè)甚至比C函數(shù)還要快。
??很多web APIs返回的都是毫秒級(jí)別的時(shí)間戳,因?yàn)閷?duì)于Javascript最終來使用或者處理數(shù)據(jù)非常快常見。只要記住將這個(gè)時(shí)間戳處以1000在傳遞給dateFromUnixTimestamp方就可以了。
原文地址—raywenderlich地址
IOS開發(fā)的25條建議和技巧-基礎(chǔ)篇
IOS開發(fā)的25條建議和技巧 – 中級(jí)篇
IOS開發(fā)的25條建議和技巧 – 高級(jí)篇
IOS開發(fā)的25條建議和技巧-總結(jié)