iOS系类教程之用instruments来检验你的app
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
發(fā)布于:2014-01-14 10:23閱讀數(shù):22668
比較了好多關(guān)于instruments 還是發(fā)現(xiàn)老外寫(xiě)的比較牛逼.于是果斷翻譯過(guò)來(lái).有能力的的可以去看英文原版,鼓勵(lì)大家看原版資料遠(yuǎn)離二手教程。原文 http://www.raywenderlich.com/23037/how-to-use-instruments-in-
“”
閱讀器
AppiOSApp開(kāi)發(fā)
比較了好多關(guān)于instruments 還是發(fā)現(xiàn)老外寫(xiě)的比較牛逼.于是果斷翻譯過(guò)來(lái).有能力的的可以去看英文原版,鼓勵(lì)大家看原版資料遠(yuǎn)離二手教程。這里是原文
?
入門
為了節(jié)省大家的時(shí)間,提供一個(gè)演示的Demo給大家。代碼傳送門.
?
下載后解壓然后用xcode打開(kāi)。
?
編譯運(yùn)行APP后 然后在搜索框內(nèi)輸入任意詞匯,點(diǎn)擊結(jié)果你會(huì)看到下面的結(jié)果
?
正如你所見(jiàn)的,這個(gè)app很簡(jiǎn)單.程序其實(shí)調(diào)用的是Flickr的API,通過(guò)app頂部的搜索框執(zhí)行搜索后在下面的tableview顯示你搜索的搜索詞,搜索詞后面的括號(hào)內(nèi)有搜索結(jié)果的個(gè)數(shù),點(diǎn)擊此行進(jìn)入一個(gè)略所圖的結(jié)果列表頁(yè)面 如上圖. 點(diǎn)擊其中一行 進(jìn)入圖像的大圖模式,在這個(gè)頁(yè)面你可以根據(jù)需要旋轉(zhuǎn)圖像。
?
到目前為止頁(yè)面看起來(lái)差不多了,你也許會(huì)想應(yīng)該可以直接提交appstore了吧.接下來(lái)這篇文章將會(huì)教你instruments工具來(lái)提高你app性能和穩(wěn)定性.
?
“時(shí)間探測(cè)器”
天下武功,唯快不破。很多公司都信奉這個(gè)教條.恨不得把a(bǔ)pp壓法周期壓縮到最低,這就導(dǎo)致了開(kāi)發(fā)中隱藏了很多問(wèn)題,有點(diǎn)經(jīng)驗(yàn)的工程師草率的優(yōu)化下,更糟的情況那些沒(méi)有經(jīng)驗(yàn)的工程師甚至不會(huì)對(duì)app進(jìn)行任何優(yōu)化.
?
某種程度上來(lái)說(shuō),你開(kāi)發(fā)過(guò)程中是可以忽略性能優(yōu)化的. 十年前,移動(dòng)設(shè)備的硬件資源是非常有限的.甚至連浮點(diǎn)數(shù)都是被禁止的.因?yàn)楦↑c(diǎn)數(shù)能導(dǎo)致代碼變大計(jì)算的速度變慢.
?
科技發(fā)展如此迅速的今天,硬件很大程度上可以彌補(bǔ)軟件的短板.現(xiàn)在的移動(dòng)設(shè)備3D硬件處理的效率甚至媲美于PC機(jī)了,但是你不能總依賴于硬件和處理器速度來(lái)掩飾你APP做的多垃圾吧.(如果安卓系統(tǒng)跑在Iphone上還能夠像iOS一樣順滑嗎?其實(shí)是一個(gè)道理的)
?
性能這個(gè)概念很抽線,所以我們必須借助數(shù)據(jù)化圖形化的輸出方式.你可能花一周的時(shí)間去優(yōu)化一個(gè)有趣的算法,但是這算法只占總執(zhí)行時(shí)間的0.5%,不管你花多少精力去優(yōu)化它,沒(méi)人會(huì)注意到.相反一個(gè)for循環(huán)花費(fèi)了90%的時(shí)間,你稍微修改下就能提高10%的效率,就是這個(gè)簡(jiǎn)單的修改可以得到大家很大的好感.因?yàn)?他們運(yùn)行app時(shí)的第一感受就是比之前快了很多.沒(méi)人會(huì)care你修改的是一個(gè)多牛逼的算法,還是一個(gè)簡(jiǎn)單的for循環(huán).
?
這個(gè)說(shuō)明了什么?
?
與其花費(fèi)時(shí)間在優(yōu)化小細(xì)節(jié)上不如多點(diǎn)時(shí)間找到你改優(yōu)化的地方.
?
下面引出第一個(gè)工具 “時(shí)間事件查看器”(自己杜撰的名字英文—Time Profiler),———他可以測(cè)量時(shí)間的間隔,中斷程序執(zhí)行,跟蹤每個(gè)線程的堆棧.你可以想象下是xcode調(diào)試時(shí)按下暫停時(shí)的畫(huà)面
?
比如,100個(gè)樣本都在做1毫秒的間隔,然后在某個(gè)方法堆棧頂部有10個(gè)樣本,你可以推算出大概的時(shí)間有10%個(gè)10毫秒花費(fèi)在此方法中,這是一個(gè)近似值.
?
廢話少說(shuō),時(shí)間是個(gè)檢測(cè)到的。
?
從xcode的菜單選擇Product-Profile,或者選擇?
程序會(huì)啟動(dòng)Instruments,這時(shí)候你會(huì)看到一個(gè)選擇窗口
?
這是instruments所有測(cè)試儀器的面板,選擇 “timer profilter” 點(diǎn)擊“profile”回啟東模擬器和app,此時(shí)會(huì)要求你輸入一次密碼,以便instruments能有權(quán)限去截獲監(jiān)聽(tīng)此進(jìn)程。
在工具窗口中,可以看到時(shí)間計(jì)數(shù),并留下了一個(gè)小箭頭移動(dòng)到右側(cè)的圖形在屏幕的中央上方。這表明該應(yīng)用程序正在運(yùn)行。
?
現(xiàn)在開(kāi)始運(yùn)行app,搜索一些圖片,這時(shí)候你發(fā)現(xiàn)查找一個(gè)結(jié)果太慢了,而且搜索結(jié)果列表頁(yè)面滾動(dòng)起來(lái)也是讓人無(wú)法忍受的。
?
首先,確保工具欄中的視圖選擇有選擇的所有三個(gè)選項(xiàng),如下所示:?
?
這將確保所有的面板都打開(kāi)。現(xiàn)在,研究下面的截圖和它下面的每個(gè)部分的解釋:
1. 錄控按鈕。中間的紅色按鈕將停止與啟動(dòng)它被點(diǎn)擊時(shí),應(yīng)用程序目前正在分析。注意這實(shí)際上是停止和啟動(dòng)應(yīng)用程序,而不是暫停它。 ?
?
2. 運(yùn)行定時(shí)器和運(yùn)行導(dǎo)航,定時(shí)器顯示APP已經(jīng)運(yùn)行了多長(zhǎng)時(shí)間,箭頭之間是可以移動(dòng)的。如果停止,然后使用錄制按鈕重新啟動(dòng)應(yīng)用程序,這將開(kāi)始一個(gè)新的運(yùn)行。顯示屏便會(huì)顯示“run2 of 2”,你可以回到第一次運(yùn)行的數(shù)據(jù),首先你停止當(dāng)前運(yùn)行,然后按下左箭頭回去。 ?
?
3. 運(yùn)行軌道。
?
4. 擴(kuò)展面板,在時(shí)間探查儀器的情況下,它是用來(lái)跟蹤顯示堆棧。 ?
?
5. 詳細(xì)地面板。它顯示了你正在使用的儀器的主要信息,這是使用頻率最高的部門,可以從它這里看到cpu運(yùn)行的時(shí)間 ??
?
6. 選項(xiàng)面板,稍后介紹。
?
重頭戲來(lái)了。
?
深究
執(zhí)行圖像搜索,并深究結(jié)果。我個(gè)人比較喜歡尋找“狗”,當(dāng)然你也可以選擇任意你想要的內(nèi)容。比如貓啊美女啊什么的。
?
現(xiàn)在上下滾動(dòng)記下列表,讓時(shí)間探測(cè)器測(cè)量下數(shù)據(jù),然后注意看下屏幕的變化和數(shù)值。這些數(shù)值反應(yīng)了CPU周期。
?
但是你也許會(huì)發(fā)現(xiàn)下面的數(shù)值太多,看你的眼花繚亂。下面打開(kāi)左邊的調(diào)用樹(shù) 然后按著如下的配置
以下介紹下配置選項(xiàng):
?
Separate by Thread: 每個(gè)線程應(yīng)該分開(kāi)考慮。只有這樣你才能揪出那些大量占用CPU的"重"線程 ?
?
Invert Call Tree: 從上倒下跟蹤堆棧,這意味著你看到的表中的方法,將已從第0幀開(kāi)始取樣,這通常你是想要的,只有這樣你才能看到CPU中話費(fèi)時(shí)間最深的方法.也就是說(shuō)FuncA{FunB{FunC}} 勾選此項(xiàng)后堆棧以C->B-A 把調(diào)用層級(jí)最深的C顯示在最外面?
?
Hide Missing Symbols: 如果dSYM無(wú)法找到你的app或者系統(tǒng)框架的話,那么表中看不到方法名只能看到十六進(jìn)制的數(shù)值,如果勾線此項(xiàng)可以隱藏這些符號(hào),便于簡(jiǎn)化數(shù)據(jù)
?
Hide System Libraries: 勾選此項(xiàng)你會(huì)顯示你app的代碼,這是非常有用的. 因?yàn)橥ǔD阒魂P(guān)心cpu花在自己代碼上的時(shí)間不是系統(tǒng)上的
?
Show Obj-C Only: 只顯示oc代碼 ,如果你的程序是像OpenGl這樣的程序,不要勾選側(cè)向因?yàn)樗锌赡苁荂++的 ?
?
Flatten Recursion: 遞歸函數(shù), 每個(gè)堆棧跟蹤一個(gè)條目
?
Top Functions: 一個(gè)函數(shù)花費(fèi)的時(shí)間直接在該函數(shù)中的總和,以及在函數(shù)調(diào)用該函數(shù)所花費(fèi)的時(shí)間的總時(shí)間。因此,如果函數(shù)A調(diào)用B,那么A的時(shí)間報(bào)告在A花費(fèi)的時(shí)間加上B.花費(fèi)的時(shí)間,這非常真有用,因?yàn)樗梢宰屇忝看蜗碌秸{(diào)用堆棧時(shí)挑最大的時(shí)間數(shù)字,歸零在你最耗時(shí)的方法。
?
如果您已啟用上述選項(xiàng),雖然有些值可能會(huì)略有不同,下面的結(jié)果的順序應(yīng)該是類似下表:
?
通過(guò)上面你能看到大部分時(shí)間都花在更新表格照片了.
?
雙擊此行,然后將會(huì)看到如下
?
那么這很有趣,不是嗎!幾乎四分之三的時(shí)間花費(fèi)在setPhoto:方法都花在創(chuàng)造照片的圖像數(shù)據(jù)!
?
現(xiàn)在可以看到的是什么問(wèn)題,NSData’s dataWithContentsOfURL 方法并不會(huì)立即返回,因?yàn)橐獜木W(wǎng)上去數(shù)據(jù),每次調(diào)用都需要長(zhǎng)達(dá)幾秒的時(shí)間返回,而此方法運(yùn)行在主線程,可想而知會(huì)有什么結(jié)果了.
?
其實(shí)為了解決這個(gè)問(wèn)題,類提供了一個(gè)ImageCache 的后臺(tái)異步下載的方法.
?
現(xiàn)在,您可以切換到Xcode和手動(dòng)找到該文件,但儀器有一個(gè)方便的“打開(kāi)Xcode中”按鈕,就在你的眼前。找到它的面板只是上面的代碼并單擊它:
?
想如下修改
-?(void)setPhoto:(FlickrPhoto?*)photo?{?????_photo?=?photo;???????self.textLabel.text?=?photo.title;f???//????NSData?*imageData?=?[NSData?dataWithContentsOfURL:_photo.thumbnailUrl];??//????self.imageView.image?=?[UIImage?imageWithData:imageData];???????[[ImageCache?sharedInstance]?downloadImageAtURL:_photo.thumbnailUrl???????????????????????????????????completionHandler:^(UIImage?*image)?{???????????????????????????????????????self.imageView.image?=?image;???????????????????????????????????????[self?setNeedsLayout];???????????????????????????????????}];?}修改好厚,在儀器重新運(yùn)行該應(yīng)用程序Product—Profile(或cmd-記住,這些快捷鍵真的會(huì)為您節(jié)省一些時(shí)間)。
?
請(qǐng)注意,這個(gè)時(shí)候會(huì)再問(wèn)一次你是否使用一起。這是因?yàn)槟氵€有一個(gè)窗口中打開(kāi)這個(gè)程序,及儀器假定您要使用相同的選項(xiàng)再次運(yùn)行。
?
執(zhí)行一些更多的搜索,并注意此時(shí)用戶界面不是那么卡頓了!這些圖像現(xiàn)在異步加載,并緩存在后臺(tái),所以一旦他們已經(jīng)被下載一次,他們不必再次下載。
?
看上去很不錯(cuò)!是時(shí)候發(fā)布了嗎? 當(dāng)然還不夠
?
分配,分配,分配
接下來(lái)的儀器是分配工具。它能給出你所有創(chuàng)建和存儲(chǔ)它們的內(nèi)存的詳細(xì)信息,它也顯示你保留了每個(gè)對(duì)象的計(jì)數(shù)。
?
關(guān)閉儀器,回到Xcode和選擇Product->Profile。然后,從選擇器分配并單擊配置文件。如下圖:
?
程序再次打開(kāi) 然后你會(huì)看到
?
這個(gè)時(shí)候你會(huì)發(fā)現(xiàn)兩個(gè)曲目。一個(gè)叫(分配)Allocations,以及一個(gè)被稱為VM Tracker(虛擬機(jī)跟蹤)。該分配軌道將詳細(xì)在本教程中討論;虛擬機(jī)跟蹤也是非常有用的,但更復(fù)雜一點(diǎn)。
?
所以你的錯(cuò)誤會(huì)追蹤下?
?
有隱藏的項(xiàng)目,你可能不知道有東西在那兒。你可能已經(jīng)聽(tīng)說(shuō)了內(nèi)存泄漏。但你可能不知道的是,其實(shí)有兩種泄漏。
?
第一個(gè)是真正的內(nèi)存泄漏,一個(gè)對(duì)象尚未被釋放,但是不再被引用的了。因此,存儲(chǔ)器不能被重新使用。
?
第二類泄漏是比較麻煩一些。這就是所謂的“無(wú)界內(nèi)存增長(zhǎng)”。這發(fā)生在內(nèi)存繼續(xù)分配,并永遠(yuǎn)不會(huì)有機(jī)會(huì)被釋放。
?
如果永遠(yuǎn)這樣下去你的程序占用的內(nèi)存會(huì)無(wú)限大,當(dāng)超過(guò)一定內(nèi)存的話 會(huì)被系統(tǒng)的看門狗給kill掉.
?
建立一個(gè)場(chǎng)景,你可以檢測(cè)出無(wú)限的內(nèi)存增長(zhǎng)。首先,在應(yīng)用程序使10個(gè)不同的搜索(不要用已經(jīng)存在的搜索)。確保搜索的一些結(jié)果!現(xiàn)在讓程序等待幾秒鐘。
?
你應(yīng)該已經(jīng)注意到,在分配的軌道圖不斷上升。這是告訴你的,內(nèi)存被分配了。它的這一特征,將引導(dǎo)你找到無(wú)限的內(nèi)存增長(zhǎng)。
?
你將要執(zhí)行的是“heap shot analysis”。為此,按這個(gè)按鈕叫“Mark Heap”。你會(huì)發(fā)現(xiàn)的詳細(xì)面板左側(cè)的按鈕
按下它,你會(huì)看到一個(gè)紅色的標(biāo)志出現(xiàn)在軌道上,像這樣:
?
heap shot分析的目的是執(zhí)行一個(gè)動(dòng)作多次,看看如果內(nèi)存是否無(wú)限增長(zhǎng)。搜索一個(gè)內(nèi)容,稍等幾秒加載圖像,然后返回主頁(yè)。然后再標(biāo)記堆。反復(fù)這樣做不同的搜索。
演戲幾個(gè)搜索后,儀器會(huì)看起來(lái)像這樣:
這時(shí)你應(yīng)該會(huì)疑問(wèn)。圖中的藍(lán)色是怎么回事了,你繼續(xù)這樣操作10次這樣的搜索 藍(lán)色還不斷變高:
?
那肯定是不好的。別急,有什么關(guān)于內(nèi)存的警告?你知道這些,對(duì)不對(duì)?內(nèi)存警告是告訴一個(gè)應(yīng)用程序,內(nèi)存警告是ios處理app最好的方式尤其是在內(nèi)存越來(lái)越吃緊的時(shí)候,你需要清除一些內(nèi)存。
?
內(nèi)存一直增長(zhǎng)其實(shí)也不一定是你的代碼除了問(wèn)題,也有可能是UIKit 系統(tǒng)框架本身導(dǎo)致的.
?
通過(guò)選擇HardwareSimulate內(nèi)存警告在iOS模擬器的菜單欄模擬內(nèi)存警告。你會(huì)發(fā)現(xiàn),記憶體使用量出現(xiàn)小幅回落,但絕對(duì)不會(huì)回到它應(yīng)該的。所以還是有無(wú)限的內(nèi)存增長(zhǎng)發(fā)生的地方。
?
究其原因,堆出手做鉆進(jìn)搜索的每次迭代后,你可以看到內(nèi)存的分配每個(gè)鏡頭之間。一起來(lái)看看在詳細(xì)信息面板,你會(huì)看到一堆一堆的鏡頭。
?
在iOS模擬器的菜單欄中選擇hardwaresimulate內(nèi)存警告模擬內(nèi)存警告。你會(huì)發(fā)現(xiàn)內(nèi)存使用會(huì)出現(xiàn)小幅回落,但肯定不會(huì)回到它應(yīng)該在的地方。
?
每一次的搜索后做你可以看到內(nèi)存已拍攝之間的分配。在詳細(xì)信息面板看一看,你會(huì)看到一好多堆鏡頭。
?
穩(wěn)準(zhǔn)狠
第一個(gè)堆鏡頭作為參照,然后隨便打開(kāi)一個(gè)堆鏡頭,你會(huì)看到如下:
?
靠,這是一個(gè)很大的對(duì)象!從哪里開(kāi)始看呢?
?
最好的方式是通過(guò)列表,你在你的應(yīng)用程序直接使用的類。在這種情況下,HTTPHeaderDict,CGRegion,CGPath,CFNumber,等等都是可以忽略了。
?
但是,一個(gè)突出的是UIImage,這肯定是在你程序使用的。點(diǎn)擊上的UIImage左側(cè)的箭頭顯示的完整列表。選擇一個(gè),在擴(kuò)展詳細(xì)信息面板:
圖中灰色的是系統(tǒng)庫(kù),黑色部分是你應(yīng)用的代碼,要獲得此跟蹤更多的上下文,雙擊唯一的黑框ImageCache方法,這時(shí)候?qū)⒌艮D(zhuǎn)到如下方法
?
-?(void)downloadImageAtURL:(NSURL*)url?completionHandler:(ImageCacheDownloadCompletionHandler)completion?{?????UIImage?*cachedImage?=?[self?imageForKey:[url?absoluteString]];?????if?(cachedImage)?{?????????completion(cachedImage);?????}?else?{?????????dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{?????????????NSData?*data?=?[NSData?dataWithContentsOfURL:url];?????????????UIImage?*image?=?[UIImage?imageWithData:data];?????????????[self?setImage:image?forKey:[url?absoluteString]];?????????????dispatch_async(dispatch_get_main_queue(),?^{?????????????????completion(image);?????????????});?????????});?????}?}?
工具是非常有用的,你現(xiàn)在要努力通過(guò)自己的代碼思考發(fā)生了什么.看看通過(guò)上面的方法,你會(huì)看到它調(diào)用一個(gè)名為setImage方法:forKey:。這種方法在緩存以防它再次使用以后的應(yīng)用程序的圖像。啊!那么這肯定聽(tīng)起來(lái)像它可能是一個(gè)問(wèn)題!
?
一起來(lái)看看該方法的實(shí)現(xiàn):
?
-?(void)setImage:(UIImage*)image?forKey:(NSString*)key?{?????[_cache?setObject:image?forKey:key];?}?
從網(wǎng)絡(luò)上下載一個(gè)圖片添加字典中,你會(huì)注意到這些圖片從來(lái)沒(méi)有從字典清楚過(guò)。
?
,這就是內(nèi)存為什么會(huì)一直增長(zhǎng),因?yàn)閼?yīng)用程序并不會(huì)從緩存里刪除東西.它只會(huì)一直增加他們。
?
要解決此問(wèn)題,你需要的是ImageCache收到UIApplication內(nèi)存吃緊的警告時(shí).清理緩存。
?
為了使ImageCache能接收通知,修改init方法如下:
?
-?(id)init?{?????if?((self?=?[super?init]))?{?????????_cache?=?[NSMutableDictionary?new];?????????[[NSNotificationCenter?defaultCenter]?addObserver:self?selector:@selector(memoryWarning:)?name:UIApplicationDidReceiveMemoryWarningNotification?object:nil];?????}?????return?self;?}?
注冊(cè)UIApplicationDidReceiveMemoryWarningNotification執(zhí)行memoryWarning:方法。
-?(void)memoryWarning:(NSNotification*)note?{?????[_cache?removeAllObjects];?}memoryWarning刪除緩存中的所有對(duì)象。這將確保沒(méi)有持圖像。
?
為了測(cè)試此修復(fù)程序,再次啟動(dòng)儀器(從Xcode中有cmd)和重復(fù)的步驟。不要忘了在模擬結(jié)束內(nèi)存警告!
?
注意:請(qǐng)確保您從Xcode中退出,重新構(gòu)建,而不是僅僅點(diǎn)擊儀器儀表上的紅色按鈕,以確保您使用的是最新的代碼。
?
這一次分析應(yīng)該是這樣的:
?
這個(gè)時(shí)候,內(nèi)存受到內(nèi)存警告后急劇下降。但還是有一些內(nèi)存整體增長(zhǎng),但遠(yuǎn)不及像以前那樣。
?
究其原因還是有一定的增長(zhǎng)確實(shí)是由于系統(tǒng)庫(kù),并沒(méi)有太多可以做的。看來(lái),系統(tǒng)庫(kù)不釋放所有的內(nèi)存,這可能是由設(shè)計(jì)或可能是一個(gè)錯(cuò)誤。你可以在你的應(yīng)用程序做的是釋放盡可能多的內(nèi)存越好,你已經(jīng)做到這一點(diǎn)!
?
干得好!還有一個(gè)問(wèn)題,修補(bǔ)了, - 仍然有泄漏,你還沒(méi)有解決的第一種類型的問(wèn)題。
?
內(nèi)存泄露
內(nèi)存泄漏的儀器。這是用來(lái)找到第一類泄漏前面提到的 - 當(dāng)一個(gè)對(duì)象不再被引用時(shí)出現(xiàn)的那種。
?
檢測(cè)泄漏是可以理解的一個(gè)很復(fù)雜的事情,但泄漏的工具記得,已分配的所有對(duì)象,并定期通過(guò)掃描每個(gè)對(duì)象以確定是否有任何不能從任何其他對(duì)象訪問(wèn)的。
?
關(guān)閉儀器,回到Xcode和選擇Product->Profile
?
回到你的應(yīng)用程序!執(zhí)行搜索,得到結(jié)果。然后點(diǎn)選結(jié)果的預(yù)覽行打開(kāi)全屏瀏覽器。按下旋轉(zhuǎn)按鈕在左上角,然后再按一次。
?
回到儀器,等待片刻。如果你已經(jīng)正確地完成上述步驟后,你會(huì)發(fā)現(xiàn)泄漏已經(jīng)出現(xiàn)了!你的工具窗口將看起來(lái)像這樣:
?
返回到模擬器,并按下旋轉(zhuǎn)幾次。然后返回到儀器和等會(huì),得到如下結(jié)果:
?
哪來(lái)的泄漏從哪里來(lái)?擴(kuò)展詳細(xì)信息面板
在擴(kuò)展的詳細(xì)信息面板打開(kāi)CGContext上名單。在列表中選擇CGContext上的元素之一,這表明導(dǎo)致要?jiǎng)?chuàng)建的對(duì)象,如下面的堆棧跟蹤:
再次,涉及到你的代碼中的幀顯示為黑色。由于只有一個(gè),雙擊它,看看代碼的方法。
?
有問(wèn)題的方法是rotateTapped: ,這是被調(diào)用時(shí)被竊聽(tīng)旋轉(zhuǎn)按鈕的處理程序。這種方法旋轉(zhuǎn)原始圖像,并創(chuàng)建一個(gè)新的圖像,如下:
-?(void)rotateTapped:(id)sender?{?????UIImage?*currentImage?=?_imageView.image;?????CGImageRef?currentCGImage?=?currentImage.CGImage;???????CGSize?originalSize?=?currentImage.size;?????CGSize?rotatedSize?=?CGSizeMake(originalSize.height,?originalSize.width);???????CGContextRef?context?=?CGBitmapContextCreate(NULL,??????????????????????????????????????????????????rotatedSize.width,??????????????????????????????????????????????????rotatedSize.height,??????????????????????????????????????????????????CGImageGetBitsPerComponent(currentCGImage),??????????????????????????????????????????????????CGImageGetBitsPerPixel(currentCGImage)?*?rotatedSize.width,??????????????????????????????????????????????????CGImageGetColorSpace(currentCGImage),??????????????????????????????????????????????????CGImageGetBitmapInfo(currentCGImage));???????CGContextTranslateCTM(context,?rotatedSize.width,?0.0f);?????CGContextRotateCTM(context,?M_PI_2);?????CGContextDrawImage(context,?(CGRect){.origin=CGPointZero,?.size=originalSize},?currentCGImage);???????CGImageRef?newCGImage?=?CGBitmapContextCreateImage(context);?????UIImage?*newImage?=?[UIImage?imageWithCGImage:newCGImage];???????self.imageView.image?=?newImage;?}再次,儀器只能在這里給你一個(gè)提示,問(wèn)題出在哪里,它不能告訴你確切位置的泄漏。這是唯一能夠證明你在創(chuàng)建對(duì)象泄露的地方.你可能認(rèn)為ARC并有不可能是造成代碼中內(nèi)存泄漏…對(duì)不對(duì)?
?
回想一下,ARC只涉及Objective-C的對(duì)象。它不管理保留和的CoreFoundation對(duì)象而不是Objective-C的對(duì)象的釋放。
?
啊,現(xiàn)在它開(kāi)始變得明顯的問(wèn)題是什么?
?
-CGContextRef和CGImageRef對(duì)象永遠(yuǎn)不會(huì)被釋放!為了解決這個(gè)問(wèn)題,在rotateTapped方法的末尾添加以下兩行代碼:
CGImageRelease(newCGImage);?CGContextRelease(context);這兩種調(diào)用都需要來(lái)維護(hù)這兩個(gè)對(duì)象的保留計(jì)數(shù)。這個(gè)說(shuō)明,你還需要了解引用計(jì)數(shù) - 即使你在你的項(xiàng)目中使用的ARC!
?
從在Xcode中,使用cmd工具構(gòu)建和運(yùn)行應(yīng)用程序。
?
在使用泄漏儀器儀器再看看應(yīng)用程序,看看是否泄漏的被固定。如果你正確地遵循上述步驟,泄漏應(yīng)消失!
轉(zhuǎn)載于:https://my.oschina.net/u/1049180/blog/396889
總結(jié)
以上是生活随笔為你收集整理的iOS系类教程之用instruments来检验你的app的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SAP期初数据导入
- 下一篇: 介绍4种HTML5 Canvas库