性能調(diào)優(yōu)(iOS)

初學(xué)者性能提升

這個(gè)部分致力于一些能提高性能的基本改變。但所有層次的開(kāi)發(fā)者都有可能會(huì)從這個(gè)記錄了一些被忽視的項(xiàng)目的小小的性能備忘錄里獲得一些提升譬涡。

1. 用ARC管理內(nèi)存

ARC(Automatic Reference Counting, 自動(dòng)引用計(jì)數(shù))和iOS5一起發(fā)布嫉到,它避免了最常見(jiàn)的也就是經(jīng)常是由于我們忘記釋放內(nèi)存所造成的內(nèi)存泄露。它自動(dòng)為你管理retain和release的過(guò)程,所以你就不必去手動(dòng)干預(yù)了
下面是你會(huì)經(jīng)常用來(lái)去創(chuàng)建一個(gè)View的代碼段:

UIView *view = [[UIView alloc] init];
 [self.view addSubview:view];
 [view release];

忘掉代碼段結(jié)尾的release簡(jiǎn)直像記得吃飯一樣簡(jiǎn)單魄藕。而ARC會(huì)自動(dòng)在底層為你做這些工作。
除了幫你避免內(nèi)存泄露撵术,ARC還可以幫你提高性能背率,它能保證釋放掉不再需要的對(duì)象的內(nèi)存。這都啥年代了嫩与,你應(yīng)該在你的所有項(xiàng)目里使用ARC!
這里有一些更多關(guān)于ARC的學(xué)習(xí)資源:

  • 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當(dāng)然不能為你排除所有內(nèi)存泄露的可能性寝姿。由于阻塞, retain 周期, 管理不完善的CoreFoundation object(還有C結(jié)構(gòu))或者就是代碼太爛依然能導(dǎo)致內(nèi)存泄露。

2. 在正確的地方使用 reuseIdentifier

一個(gè)開(kāi)發(fā)中常見(jiàn)的錯(cuò)誤就是沒(méi)有給UITableViewCells划滋, UICollectionViewCells饵筑,甚至是UITableViewHeaderFooterViews設(shè)置正確的reuseIdentifier
為了性能最優(yōu)化处坪,table view用 tableView:cellForRowAtIndexPath: 為rows分配cells的時(shí)候根资,它的數(shù)據(jù)應(yīng)該重用自UITableViewCell。 一個(gè)table view維持一個(gè)隊(duì)列的數(shù)據(jù)可重用的UITableViewCell對(duì)象稻薇。
不使用reuseIdentifier的話嫂冻,每顯示一行table view就不得不設(shè)置全新的cell。這對(duì)性能的影響可是相當(dāng)大的塞椎,尤其會(huì)使app的滾動(dòng)體驗(yàn)大打折扣桨仿。
自iOS6起,除了UICollectionView的cells和補(bǔ)充views案狠,你也應(yīng)該在header和footer views中使用reuseIdentifiers服傍。
想要使用reuseIdentifiers的話钱雷,在一個(gè)table view中添加一個(gè)新的cell時(shí)在data source object中添加這個(gè)方法:

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

這個(gè)方法把那些已經(jīng)存在的cell從隊(duì)列中排除,或者在必要時(shí)使用先前注冊(cè)的nib或者class創(chuàng)造新的cell吹零。如果沒(méi)有可重用的cell罩抗,你也沒(méi)有注冊(cè)一個(gè)class或者nib的話,這個(gè)方法返回nil灿椅。

3. 盡量把views設(shè)置為透明

如果你有透明的Views你應(yīng)該設(shè)置它們的opaque屬性為YES套蒂。
原因是這會(huì)使系統(tǒng)用一個(gè)最優(yōu)的方式渲染這些views。這個(gè)簡(jiǎn)單的屬性在IB或者代碼里都可以設(shè)定茫蛹。
Apple的文檔對(duì)于為圖片設(shè)置透明屬性的描述是:
(opaque)這個(gè)屬性給渲染系統(tǒng)提供了一個(gè)如何處理這個(gè)view的提示操刀。如果設(shè)為YES, 渲染系統(tǒng)就認(rèn)為這個(gè)view是完全不透明的婴洼,這使得渲染系統(tǒng)優(yōu)化一些渲染過(guò)程和提高性能骨坑。如果設(shè)置為NO,渲染系統(tǒng)正常地和其它內(nèi)容組成這個(gè)View柬采。默認(rèn)值是YES欢唾。
在相對(duì)比較靜止的畫(huà)面中,設(shè)置這個(gè)屬性不會(huì)有太大影響粉捻。然而當(dāng)這個(gè)view嵌在scroll view里邊礁遣,或者是一個(gè)復(fù)雜動(dòng)畫(huà)的一部分,不設(shè)置這個(gè)屬性的話會(huì)在很大程度上影響app的性能杀迹。
你可以在模擬器中用Debug\Color Blended Layers選項(xiàng)來(lái)發(fā)現(xiàn)哪些view沒(méi)有被設(shè)置為opaque亡脸。目標(biāo)就是押搪,能設(shè)為opaque的就全設(shè)為opaque!

4. 避免過(guò)于龐大的XIB

iOS5中加入的Storyboards(分鏡)正在快速取代XIB树酪。然而XIB在一些場(chǎng)景中仍然很有用。比如你的app需要適應(yīng)iOS5之前的設(shè)備大州,或者你有一個(gè)自定義的可重用的view,你就不可避免地要用到他們续语。
如果你不得不XIB的話,使他們盡量簡(jiǎn)單厦画。嘗試為每個(gè)Controller配置一個(gè)單獨(dú)的XIB疮茄,盡可能把一個(gè)View Controller的view層次結(jié)構(gòu)分散到單獨(dú)的XIB中去。
需要注意的是根暑,當(dāng)你加載一個(gè)XIB的時(shí)候所有內(nèi)容都被放在了內(nèi)存里力试,包括任何圖片。如果有一個(gè)不會(huì)即刻用到的view排嫌,你這就是在浪費(fèi)寶貴的內(nèi)存資源了畸裳。Storyboards就是另一碼事兒了,storyboard僅在需要時(shí)實(shí)例化一個(gè)view controller.
當(dāng)家在XIB是淳地,所有圖片都被chache怖糊,如果你在做OS X開(kāi)發(fā)的話帅容,聲音文件也是。Apple在相關(guān)文檔中的記述是:
當(dāng)你加載一個(gè)引用了圖片或者聲音資源的nib時(shí)伍伤,nib加載代碼會(huì)把圖片和聲音文件寫(xiě)進(jìn)內(nèi)存并徘。在OS X中,圖片和聲音資源被緩存在named cache中以便將來(lái)用到時(shí)獲取扰魂。在iOS中麦乞,僅圖片資源會(huì)被存進(jìn)named caches。取決于你所在的平臺(tái)劝评,使用NSImage 或UIImage 的imageNamed:方法來(lái)獲取圖片資源路幸。

5. 不要阻塞主線程

永遠(yuǎn)不要使主線程承擔(dān)過(guò)多。因?yàn)閁IKit在主線程上做所有工作付翁,渲染简肴,管理觸摸反應(yīng),回應(yīng)輸入等都需要在它上面完成百侧。
一直使用主線程的風(fēng)險(xiǎn)就是如果你的代碼真的block了主線程砰识,你的app會(huì)失去反應(yīng)。這佣渴。辫狼。。正是在App Store中拿到一顆星的捷徑 :]
大部分阻礙主進(jìn)程的情形是你的app在做一些牽涉到讀寫(xiě)外部資源的I/O操作辛润,比如存儲(chǔ)或者網(wǎng)絡(luò)膨处。

6. 在Image Views中調(diào)整圖片大小

如果要在UIImageView中顯示一個(gè)來(lái)自bundle的圖片,你應(yīng)保證圖片的大小和UIImageView的大小相同砂竖。在運(yùn)行中縮放圖片是很耗費(fèi)資源的真椿,特別是UIImageView嵌套在UIScrollView中的情況下。
如果圖片是從遠(yuǎn)端服務(wù)加載的你不能控制圖片大小乎澄,比如在下載前調(diào)整到合適大小的話突硝,你可以在下載完成后,最好是用background thread置济,縮放一次解恰,然后在UIImageView中使用縮放后的圖片。

7. 選擇正確的Collection

學(xué)會(huì)選擇對(duì)業(yè)務(wù)場(chǎng)景最合適的類或者對(duì)象是寫(xiě)出能效高的代碼的基礎(chǔ)浙于。當(dāng)處理collections時(shí)這句話尤其正確护盈。
Apple有一個(gè) Collections Programming Topics 的文檔詳盡介紹了可用的classes間的差別和你該在哪些場(chǎng)景中使用它們。這對(duì)于任何使用collections的人來(lái)說(shuō)是一個(gè)必讀的文檔羞酗。下面是一些常見(jiàn)的總結(jié)

  • Arrays: 有序的一組值腐宋。使用index來(lái)lookup很快,使用value lookup很慢, 插入/刪除很慢脏款。
  • Dictionaries: 存儲(chǔ)鍵值對(duì)围苫。 用鍵來(lái)查找比較快。
  • Sets: 無(wú)序的一組值撤师。用值來(lái)查找很快剂府,插入/刪除很快。

8. 打開(kāi)gzip壓縮

大量app依賴于遠(yuǎn)端資源和第三方API剃盾,你可能會(huì)開(kāi)發(fā)一個(gè)需要從遠(yuǎn)端下載XML, JSON, HTML或者其它格式的app腺占。
問(wèn)題是我們的目標(biāo)是移動(dòng)設(shè)備,因此你就不能指望網(wǎng)絡(luò)狀況有多好痒谴。一個(gè)用戶現(xiàn)在還在edge網(wǎng)絡(luò)衰伯,下一分鐘可能就切換到了3G。不論什么場(chǎng)景积蔚,你肯定不想讓你的用戶等太長(zhǎng)時(shí)間意鲸。
減小文檔的一個(gè)方式就是在服務(wù)端和你的app中打開(kāi)gzip。這對(duì)于文字這種能有更高壓縮率的數(shù)據(jù)來(lái)說(shuō)會(huì)有更顯著的效用尽爆。
好消息是怎顾,iOS已經(jīng)在NSURLConnection中默認(rèn)支持了gzip壓縮,當(dāng)然AFNetworking這些基于它的框架亦然漱贱。像Google App Engine這些云服務(wù)提供者也已經(jīng)支持了壓縮輸出槐雾。

中級(jí)性能提升

9. 重用和延遲加載(lazy load) Views

更多的view意味著更多的渲染,也就是更多的CPU和內(nèi)存消耗幅狮,對(duì)于那種嵌套了很多view在UIScrollView里邊的app更是如此募强。
這里我們用到的技巧就是模仿UITableViewUICollectionView的操作: 不要一次創(chuàng)建所有的subview,而是當(dāng)需要時(shí)才創(chuàng)建崇摄,當(dāng)它們完成了使命擎值,把他們放進(jìn)一個(gè)可重用的隊(duì)列中。
這樣的話你就只需要在滾動(dòng)發(fā)生時(shí)創(chuàng)建你的views配猫,避免了不劃算的內(nèi)存分配幅恋。
創(chuàng)建views的能效問(wèn)題也適用于你app的其它方面。想象一下一個(gè)用戶點(diǎn)擊一個(gè)按鈕的時(shí)候需要呈現(xiàn)一個(gè)view的場(chǎng)景泵肄。有兩種實(shí)現(xiàn)方法:

  1. 創(chuàng)建并隱藏這個(gè)view當(dāng)這個(gè)screen加載的時(shí)候,當(dāng)需要時(shí)顯示它淑翼;
  2. 當(dāng)需要時(shí)才創(chuàng)建并展示腐巢。
    每個(gè)方案都有其優(yōu)缺點(diǎn)。
    用第一種方案的話因?yàn)槟阈枰婚_(kāi)始就創(chuàng)建一個(gè)view并保持它直到不再使用玄括,這就會(huì)更加消耗內(nèi)存冯丙。然而這也會(huì)使你的app操作更敏感因?yàn)楫?dāng)用戶點(diǎn)擊按鈕的時(shí)候它只需要改變一下這個(gè)view的可見(jiàn)性。
    第二種方案則相反-消耗更少內(nèi)存,但是會(huì)在點(diǎn)擊按鈕的時(shí)候比第一種稍顯卡頓胃惜。

10. Cache

一個(gè)極好的原則就是泞莉,緩存所需要的,也就是那些不大可能改變但是需要經(jīng)常讀取的東西船殉。
我們能緩存些什么呢鲫趁?一些選項(xiàng)是,遠(yuǎn)端服務(wù)器的響應(yīng)利虫,圖片挨厚,甚至計(jì)算結(jié)果。

11. 權(quán)衡渲染方法

在iOS中可以有很多方法做出漂亮的按鈕糠惫。你可以用整幅的圖片疫剃,可調(diào)大小的圖片,uozhe可以用CALayer硼讽, CoreGraphics甚至OpenGL來(lái)畫(huà)它們巢价。
當(dāng)然每個(gè)不同的解決方法都有不同的復(fù)雜程度和相應(yīng)的性能。
簡(jiǎn)單來(lái)說(shuō)固阁,就是用事先渲染好的圖片更快一些蹄溉,因?yàn)槿绱艘粊?lái)iOS就免去了創(chuàng)建一個(gè)圖片再畫(huà)東西上去然后顯示在屏幕上的程序。問(wèn)題是你需要把所有你需要用到的圖片放到app的bundle里面您炉,這樣就增加了體積 – 這就是使用可變大小的圖片更好的地方了: 你可以省去一些不必要的空間柒爵,也不需要再為不同的元素(比如按鈕)來(lái)做不同的圖。
然而赚爵,使用圖片也意味著你失去了使用代碼調(diào)整圖片的機(jī)動(dòng)性棉胀,你需要一遍又一遍不斷地重做他們,這樣就很浪費(fèi)時(shí)間了冀膝,而且你如果要做一個(gè)動(dòng)畫(huà)效果唁奢,雖然每幅圖只是一些細(xì)節(jié)的變化你就需要很多的圖片造成bundle大小的不斷增大。
總得來(lái)說(shuō)窝剖,你需要權(quán)衡一下利弊麻掸,到底是要性能能還是要bundle保持合適的大小。

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

一旦系統(tǒng)內(nèi)存過(guò)低赐纱,iOS會(huì)通知所有運(yùn)行中app脊奋。在官方文檔中是這樣記述:
如果你的app收到了內(nèi)存警告,它就需要盡可能釋放更多的內(nèi)存疙描。最佳方式是移除對(duì)緩存诚隙,圖片object和其他一些可以重創(chuàng)建的objects的strong references.
幸運(yùn)的是,UIKit提供了幾種收集低內(nèi)存警告的方法:
? 在app delegate中使用applicationDidReceiveMemoryWarning: 的方法
? 在你的自定義UIViewController的子類(subclass)中覆蓋didReceiveMemoryWarning
? 注冊(cè)并接收 UIApplicationDidReceiveMemoryWarningNotification 的通知
一旦收到這類通知起胰,你就需要釋放任何不必要的內(nèi)存使用久又。
例如,UIViewController的默認(rèn)行為是移除一些不可見(jiàn)的view, 它的一些子類則可以補(bǔ)充這個(gè)方法地消,刪掉一些額外的數(shù)據(jù)結(jié)構(gòu)炉峰。一個(gè)有圖片緩存的app可以移除不在屏幕上顯示的圖片。
這樣對(duì)內(nèi)存警報(bào)的處理是很必要的脉执,若不重視疼阔,你的app就可能被系統(tǒng)殺掉。
然而适瓦,當(dāng)你一定要確認(rèn)你所選擇的object是可以被重現(xiàn)創(chuàng)建的來(lái)釋放內(nèi)存竿开。一定要在開(kāi)發(fā)中用模擬器中的內(nèi)存提醒模擬去測(cè)試一下。

13. 重用大開(kāi)銷(xiāo)對(duì)象

一些objects的初始化很慢玻熙,比如NSDateFormatter和NSCalendar否彩。然而,你又不可避免地需要使用它們嗦随,比如從JSON或者XML中解析數(shù)據(jù)列荔。
想要避免使用這個(gè)對(duì)象的瓶頸你就需要重用他們,可以通過(guò)添加屬性到你的class里或者創(chuàng)建靜態(tài)變量來(lái)實(shí)現(xiàn)枚尼。
注意如果你要選擇第二種方法贴浙,對(duì)象會(huì)在你的app運(yùn)行時(shí)一直存在于內(nèi)存中,和單例(singleton)很相似署恍。

14. 避免反復(fù)處理數(shù)據(jù)

許多應(yīng)用需要從服務(wù)器加載功能所需的常為JSON或者XML格式的數(shù)據(jù)崎溃。在服務(wù)器端和客戶端使用相同的數(shù)據(jù)結(jié)構(gòu)很重要。在內(nèi)存中操作數(shù)據(jù)使它們滿足你的數(shù)據(jù)結(jié)構(gòu)是開(kāi)銷(xiāo)很大的盯质。
比如你需要數(shù)據(jù)來(lái)展示一個(gè)table view,最好直接從服務(wù)器取array結(jié)構(gòu)的數(shù)據(jù)以避免額外的中間數(shù)據(jù)結(jié)構(gòu)改變袁串。
類似的,如果需要從特定key中取數(shù)據(jù)呼巷,那么就使用鍵值對(duì)的dictionary囱修。

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

從app和網(wǎng)絡(luò)服務(wù)間傳輸數(shù)據(jù)有很多方案,最常見(jiàn)的就是JSON和XML王悍。你需要選擇對(duì)你的app來(lái)說(shuō)最合適的一個(gè)破镰。
解析JSON會(huì)比XML更快一些,JSON也通常更小更便于傳輸压储。從iOS5起有了官方內(nèi)建的JSON deserialization 就更加方便使用了鲜漩。
但是XML也有XML的好處,比如使用SAX 來(lái)解析XML就像解析本地文件一樣渠脉,你不需像解析json一樣等到整個(gè)文檔下載完成才開(kāi)始解析宇整。當(dāng)你處理很大的數(shù)據(jù)的時(shí)候就會(huì)極大地減低內(nèi)存消耗和增加性能。

16. 減少使用Web特性

UIWebView很有用芋膘,用它來(lái)展示網(wǎng)頁(yè)內(nèi)容或者創(chuàng)建UIKit很難做到的動(dòng)畫(huà)效果是很簡(jiǎn)單的一件事。
但是你可能有注意到UIWebView并不像驅(qū)動(dòng)Safari的那么快。這是由于以JIT compilation 為特色的Webkit的Nitro Engine的限制为朋。
所以想要更高的性能你就要調(diào)整下你的HTML了臂拓。第一件要做的事就是盡可能移除不必要的javascript,避免使用過(guò)大的框架习寸。能只用原生js就更好了胶惰。
另外,盡可能異步加載例如用戶行為統(tǒng)計(jì)script這種不影響頁(yè)面表達(dá)的javascript霞溪。
最后孵滞,永遠(yuǎn)要注意你使用的圖片,保證圖片的符合你使用的大小鸯匹。使用Sprite sheet提高加載速度和節(jié)約內(nèi)存坊饶。

17. 設(shè)定Shadow Path

如何在一個(gè)View或者一個(gè)layer上加一個(gè)shadow呢,QuartzCore框架是很多開(kāi)發(fā)者的選擇:

#import <QuartzCore/QuartzCore.h>
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;

看起來(lái)很簡(jiǎn)單殴蓬,對(duì)吧匿级。
可是,壞消息是使用這個(gè)方法也有它的問(wèn)題… Core Animation不得不先在后臺(tái)得出你的圖形并加好陰影然后才渲染染厅,這開(kāi)銷(xiāo)是很大的痘绎。
使用shadowPath的話就避免了這個(gè)問(wèn)題:
view.layer.shadowPath = [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];
使用shadow path的話iOS就不必每次都計(jì)算如何渲染,它使用一個(gè)預(yù)先計(jì)算好的路徑肖粮。但問(wèn)題是自己計(jì)算path的話可能在某些View中比較困難孤页,且每當(dāng)view的frame變化的時(shí)候你都需要去update shadow path.

17. 優(yōu)化Table View

Table view需要有很好的滾動(dòng)性能,不然用戶會(huì)在滾動(dòng)過(guò)程中發(fā)現(xiàn)動(dòng)畫(huà)的瑕疵涩馆。
為了保證table view平滑滾動(dòng)行施,確保你采取了以下的措施:
? 正確使用reuseIdentifier來(lái)重用cells
? 盡量使所有的view opaque,包括cell自身
? 避免漸變凌净,圖片縮放悲龟,后臺(tái)選人
? 緩存行高
? 如果cell內(nèi)現(xiàn)實(shí)的內(nèi)容來(lái)自web,使用異步加載冰寻,緩存請(qǐng)求結(jié)果
? 使用shadowPath來(lái)畫(huà)陰影
? 減少subviews的數(shù)量
? 盡量不適用cellForRowAtIndexPath:须教,如果你需要用到它,只用一次然后緩存結(jié)果
? 使用正確的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)
? 使用rowHeight, sectionFooterHeightsectionHeaderHeight來(lái)設(shè)定固定的高斩芭,不要請(qǐng)求delegate

18. 選擇正確的數(shù)據(jù)存儲(chǔ)選項(xiàng)

當(dāng)存儲(chǔ)大塊數(shù)據(jù)時(shí)你會(huì)怎么做轻腺?
你有很多選擇,比如:
? 使用NSUerDefaults
? 使用XML, JSON, 或者 plist
? 使用NSCoding存檔
? 使用類似SQLite的本地SQL數(shù)據(jù)庫(kù)
? 使用 Core Data
NSUserDefaults的問(wèn)題是什么划乖?雖然它很nice也很便捷贬养,但是它只適用于小數(shù)據(jù),比如一些簡(jiǎn)單的布爾型的設(shè)置選項(xiàng)琴庵,再大點(diǎn)你就要考慮其它方式了
XML這種結(jié)構(gòu)化檔案呢误算?總體來(lái)說(shuō)仰美,你需要讀取整個(gè)文件到內(nèi)存里去解析,這樣是很不經(jīng)濟(jì)的儿礼。使用SAX又是一個(gè)很麻煩的事情团驱。
NSCoding朽们?不幸的是,它也需要讀寫(xiě)文件,所以也有以上問(wèn)題献烦。
在這種應(yīng)用場(chǎng)景下蚕冬,使用SQLite 或者 Core Data比較好橘洞。使用這些技術(shù)你用特定的查詢語(yǔ)句就能只加載你需要的對(duì)象夹孔。
在性能層面來(lái)講,SQLite和Core Data是很相似的琅轧。他們的不同在于具體使用方法伍绳。Core Data代表一個(gè)對(duì)象的graph model,但SQLite就是一個(gè)DBMS鹰晨。Apple在一般情況下建議使用Core Data墨叛,但是如果你有理由不使用它,那么就去使用更加底層的SQLite吧模蜡。
如果你使用SQLite漠趁,你可以用FMDB這個(gè)庫(kù)來(lái)簡(jiǎn)化SQLite的操作,這樣你就不用花很多經(jīng)歷了解SQLite的C API了忍疾。

19. 加速啟動(dòng)時(shí)間

快速打開(kāi)app是很重要的闯传,特別是用戶第一次打開(kāi)它時(shí),對(duì)app來(lái)講卤妒,第一印象太太太重要了甥绿。
你能做的就是使它盡可能做更多的異步任務(wù),比如加載遠(yuǎn)端或者數(shù)據(jù)庫(kù)數(shù)據(jù)则披,解析數(shù)據(jù)共缕。
還是那句話,避免過(guò)于龐大的XIB士复,因?yàn)樗麄兪窃谥骶€程上加載的图谷。所以盡量使用沒(méi)有這個(gè)問(wèn)題的Storyboards吧!

20. 使用Autorelease Pool

NSAutoreleasePool負(fù)責(zé)釋放block中的autoreleased objects阱洪。一般情況下它會(huì)自動(dòng)被UIKit調(diào)用便贵。但是有些狀況下你也需要手動(dòng)去創(chuàng)建它。
假如你創(chuàng)建很多臨時(shí)對(duì)象冗荸,你會(huì)發(fā)現(xiàn)內(nèi)存一直在減少直到這些對(duì)象被release的時(shí)候承璃。這是因?yàn)橹挥挟?dāng)UIKit用光了autorelease pool的時(shí)候memory才會(huì)被釋放。
好消息是你可以在你自己的@autoreleasepool里創(chuàng)建臨時(shí)的對(duì)象來(lái)避免這個(gè)行為:

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. */
    }
}

21. 選擇是否緩存圖片

常見(jiàn)的從bundle中加載圖片的方式有兩種蚌本,一個(gè)是用imageNamed盔粹,二是用imageWithContentsOfFile隘梨,第一種比較常見(jiàn)一點(diǎn)。
既然有兩種類似的方法來(lái)實(shí)現(xiàn)相同的目的玻佩,那么他們之間的差別是什么呢出嘹?
imageNamed的優(yōu)點(diǎn)是當(dāng)加載時(shí)會(huì)緩存圖片席楚。imageNamed的文檔中這么說(shuō):
這個(gè)方法用一個(gè)指定的名字在系統(tǒng)緩存中查找并返回一個(gè)圖片對(duì)象如果它存在的話咬崔。如果緩存中沒(méi)有找到相應(yīng)的圖片,這個(gè)方法從指定的文檔中加載然后緩存并返回這個(gè)對(duì)象烦秩。
相反的垮斯,imageWithContentsOfFile僅加載圖片。

UIImage *img = [UIImage imageNamed:@"myImage"];// caching
 // or
 UIImage *img = [UIImage imageWithContentsOfFile:@"myImage"];// no caching

那么我們應(yīng)該如何選擇呢只祠?
如果你要加載一個(gè)大圖片而且是一次性使用兜蠕,那么就沒(méi)必要緩存這個(gè)圖片,用imageWithContentsOfFile足矣抛寝,這樣不會(huì)浪費(fèi)內(nèi)存來(lái)緩存它熊杨。
然而,在圖片反復(fù)重用的情況下imageNamed是一個(gè)好得多的選擇盗舰。

22. 避免日期格式轉(zhuǎn)換

如果你要用NSDateFormatter來(lái)處理很多日期格式晶府,應(yīng)該小心以待。就像先前提到的钻趋,任何時(shí)候重用NSDateFormatters都是一個(gè)好的實(shí)踐川陆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛮位,隨后出現(xiàn)的幾起案子较沪,更是在濱河造成了極大的恐慌,老刑警劉巖失仁,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尸曼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡萄焦,警方通過(guò)查閱死者的電腦和手機(jī)控轿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)楷扬,“玉大人解幽,你說(shuō)我怎么就攤上這事『嫫唬” “怎么了躲株?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)镣衡。 經(jīng)常有香客問(wèn)我霜定,道長(zhǎng)档悠,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任望浩,我火速辦了婚禮辖所,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘磨德。我一直安慰自己缘回,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布典挑。 她就那樣靜靜地躺著酥宴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪您觉。 梳的紋絲不亂的頭發(fā)上拙寡,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音琳水,去河邊找鬼肆糕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛在孝,可吹牛的內(nèi)容都是我干的诚啃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浑玛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼绍申!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起顾彰,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤极阅,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后涨享,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體筋搏,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年厕隧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奔脐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吁讨,死狀恐怖髓迎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情建丧,我是刑警寧澤排龄,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站翎朱,受9級(jí)特大地震影響橄维,放射性物質(zhì)發(fā)生泄漏尺铣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一争舞、第九天 我趴在偏房一處隱蔽的房頂上張望凛忿。 院中可真熱鬧,春花似錦竞川、人聲如沸店溢。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逞怨。三九已至,卻和暖如春福澡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驹马。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工革砸, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糯累。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓算利,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親泳姐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子效拭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容