iOS 性能調(diào)優(yōu),成為一名合格iOS程序員必須掌握的技能

Tip: 很多大大留言說(shuō)附井,不能登錄讼庇,沒(méi)法看,因?yàn)樾枰赮WWeiBoCommon.swift文件里面配置 自己的微博AppKey等信息雅采,其實(shí)只要看了評(píng)論的人,就知道怎么回事了慨亲,因?yàn)閱?wèn)的比較多婚瓜,所以在這里說(shuō)一下,就不一一回復(fù)了
提供了基于Swift3.0模仿的新浪微博的Demo刑棵,大家可以下載看一看:基于Swift3.0高仿的微博客戶端,里面針對(duì)于微博首頁(yè)的復(fù)雜頁(yè)面的優(yōu)化做了很多的處理巴刻,頁(yè)面的FPS 一直保持在59 ~ 60 。
看下demo的效果:

FPS測(cè)試.gif

CPU 和GPU

關(guān)于繪圖和動(dòng)畫有兩種處理方式CPU(中央處理器)和GPU(圖形處理器)蛉签,CPU的工作都在軟件層面胡陪,而GPU的在硬件層面。
總的來(lái)說(shuō)碍舍,可以使用CPU做任何事情柠座,但是對(duì)于圖像的處理,通常GPU會(huì)更快片橡,因?yàn)镚PU使用圖像對(duì)高度并行浮點(diǎn)運(yùn)算做了優(yōu)化(盡管我也不知道是什么鬼妈经??)捧书,所以吹泡,我們想盡可能的把屏幕渲染的工作交給硬件去處理,而問(wèn)題在于GPU并沒(méi)有無(wú)限制處理的性能经瓷,一旦資源用盡爆哑,即使CPU并沒(méi)有完全占用,GPU性能還是會(huì)下降了嚎。
所以泪漂,目前大多的性能優(yōu)化都是關(guān)于智能利用GPU和CPU,平衡它們之間工作負(fù)載歪泳。

測(cè)量萝勤,而不是猜測(cè)

現(xiàn)在知道哪些可能會(huì)影響性能,該如何修復(fù)呢呐伞?有許多傳統(tǒng)的詭計(jì)來(lái)優(yōu)化敌卓,但如果盲目使用的話,可能會(huì)造成更多性能上的問(wèn)題伶氢,而不是優(yōu)化了
如何正確的測(cè)量而不是猜測(cè)這點(diǎn)很重要趟径,根據(jù)性能相關(guān)知識(shí)寫出的代碼不同于倉(cāng)促優(yōu)化瘪吏,前者是正確的姿勢(shì),后者則是在浪費(fèi)生命
那改如何測(cè)量蜗巧,第一步就是確保在真實(shí)環(huán)境下測(cè)試你的程序

真機(jī)測(cè)試掌眠,而不是模擬器

當(dāng)你開(kāi)始做一些性能方面的工作時(shí)候,一定要在真機(jī)上測(cè)試幕屹,而不是模擬器蓝丙,模擬器雖然可以加快開(kāi)發(fā)效率,但卻不能準(zhǔn)確提供真機(jī)的性能參數(shù)
模擬器運(yùn)行在Mac上望拖,然而Mac上的cpu比ios設(shè)備要快很多渺尘,相反,Mac上的GPU和ios設(shè)備上的不一樣说敏,模擬器不得已需要在軟件層面(CPU)模擬ios設(shè)備鸥跟,所以GPU的相關(guān)操作在模擬器上面運(yùn)行的會(huì)更慢
另一件重要的就是性能測(cè)試的時(shí)候一定要用發(fā)布配置,而不是調(diào)試模式盔沫,因?yàn)楫?dāng)用發(fā)布環(huán)境打包的時(shí)候医咨,編譯器會(huì)引入一些提高性能的優(yōu)化,比如:去除調(diào)試符號(hào)或者移除并重新組織代碼迅诬,因?yàn)榭梢宰约鹤龅竭@些腋逆,比如禁用NSlog、print語(yǔ)句侈贷,因?yàn)?惩歉,只需要關(guān)心發(fā)布性能。

測(cè)試幀率

可以在程序中使用CADisplayLink來(lái)測(cè)量幀率俏蛮,在屏幕上顯示出來(lái),我用Swift3.0模仿YY大神的代碼寫了一個(gè)簡(jiǎn)單的FPS指示器 YWFPSLabel,使用CADisplayLink監(jiān)視FPS數(shù)值撑蚌,日常開(kāi)發(fā)的時(shí)候,可以有直接的體現(xiàn)搏屑,不用再靠猜了...
YWFPSLabel集成也很方便,在AppDelegate的application方法里加下面兩句即可

        let FPSLab = YWFPSLabel(frame: CGRect())
        UIApplication.shared.keyWindow!.addSubview(FPSLab)

不知道大家有木有看到頭部那個(gè)小label啊~~~
但是應(yīng)用內(nèi)的FPS顯示并不能完全真實(shí)的測(cè)量出性能争涌,因?yàn)樗鼉H僅能測(cè)試出應(yīng)用內(nèi)的幀率,還有很多是動(dòng)畫都是在應(yīng)用外發(fā)生(在渲染進(jìn)程中處理)辣恋,但應(yīng)用內(nèi)FPS計(jì)數(shù)可以對(duì)一些性能問(wèn)題提供參考亮垫,一旦找到問(wèn)題,需要更多的精確詳細(xì)信息來(lái)定位問(wèn)題所在伟骨,我們就要使用Instuments了饮潦,它可以看到更多準(zhǔn)確是信息,查看到所有與顯示的數(shù)據(jù)携狭。

Instuments

Instuments是Xcode套件中沒(méi)有被充分利用的工具继蜡,很多iOS開(kāi)發(fā)者從來(lái)沒(méi)用過(guò)Instrument,特別是通過(guò)短暫培訓(xùn)出來(lái)的同學(xué)們,所以稀并,很多面試官也會(huì)問(wèn)性能條調(diào)優(yōu)方面的知識(shí)仅颇,來(lái)判斷面試的同學(xué)是否真正應(yīng)用對(duì)年開(kāi)發(fā)經(jīng)驗(yàn)。

  • Activity Monitor

個(gè)人覺(jué)的很像Windows的任務(wù)管理器碘举,可以查看所有的進(jìn)程忘瓦,以及進(jìn)程的內(nèi)存、cpu使用百分比等數(shù)據(jù)等殴俱,就不多介紹了政冻,打開(kāi)一看大概就知道怎么回事

  • Allocations

管理內(nèi)存是app開(kāi)發(fā)中最重要的一個(gè)方面枚抵,對(duì)于開(kāi)發(fā)者來(lái)說(shuō)线欲,在程序架構(gòu)中減少內(nèi)存的使用通常都是使用Allocations去定位和找出減少內(nèi)存使用的方式
接下來(lái),談一下內(nèi)存泄漏的兩種情況

  • 第一種:為對(duì)象A申請(qǐng)了內(nèi)存空間汽摹,之后再也沒(méi)用過(guò)對(duì)象A李丰,也沒(méi)釋放過(guò)A導(dǎo)致內(nèi)存泄漏,這種是Leaked Memory內(nèi)存泄漏
  • 第二種:類似于遞歸逼泣,不斷地申請(qǐng)內(nèi)存空間導(dǎo)致的內(nèi)存泄漏趴泌,這種情況是Abandoned Momory
    此工具可以讓開(kāi)發(fā)者很好的了解每個(gè)方法占用內(nèi)存的情況,并定位相關(guān)的代碼


    Allocations查看方法占用內(nèi)存.png

    右鍵就可以打開(kāi)Xcode自動(dòng)定位到相關(guān)占用內(nèi)存方法的代碼上

定位到相關(guān)代碼.png

第二種情況可以根據(jù)下圖的操作清晰的找到對(duì)用的代碼問(wèn)題

定位Abandoned Momory.png

解釋一下拉庶,第二種情況我們應(yīng)該如何操作嗜憔,重復(fù)的執(zhí)行一系列的操作時(shí)候內(nèi)存不會(huì)繼續(xù)增加,比如打開(kāi)和關(guān)閉一個(gè)窗口氏仗,這樣的操作吉捶,每一次操作的前后,內(nèi)存應(yīng)該是相同的皆尔,通過(guò)多次循環(huán)操作呐舔,內(nèi)存不會(huì)遞增下去,通過(guò)這種分析結(jié)果慷蠕,觀察內(nèi)存分配趨勢(shì)珊拼,當(dāng)發(fā)現(xiàn)不正確的結(jié)果或者矛盾的結(jié)果,就可以研究是不是Abandoned Momory的問(wèn)題流炕,并可以修正這個(gè)問(wèn)題了

Core Animation

之前說(shuō)過(guò)自己寫的YWFPSLabel只能檢測(cè)應(yīng)用內(nèi)的FPS,而此工具考慮到了程序外的動(dòng)畫澎现,理想的FPS值為60左右,過(guò)低的話就用該進(jìn)性優(yōu)化了每辟,根據(jù)WWDC的說(shuō)法剑辫,當(dāng)FPS 低于45的時(shí)候,用戶就會(huì)察覺(jué)到到滑動(dòng)有卡頓

Core Animation.png

圈著數(shù)字紅色方框中的數(shù)字影兽,代表著FPS值揭斧,理論上60最佳,實(shí)際過(guò)程中59就可以了,說(shuō)明就是很流暢的讹开,說(shuō)明一下操作方式:在手指不離開(kāi)屏幕的情況下盅视,上下滑動(dòng)屏幕列表
介紹一下Deug Display中選項(xiàng)的作用

  • Color Blended Layers(混合過(guò)度繪制)

打開(kāi)此選項(xiàng)屏幕的效果圖如下:


Color Blended Layers.jpg

這個(gè)選項(xiàng)基于渲染程度對(duì)屏幕中的混合區(qū)域進(jìn)行綠到紅的高亮(也就是多個(gè)半透明圖層的疊加),由于重繪的原因旦万,混合對(duì)GPU性能會(huì)有影響闹击,同時(shí)也是滑動(dòng)或者動(dòng)畫掉幀的罪魁禍?zhǔn)字?br> GPU每一幀的繪制的像素有最大限制,這個(gè)情況下可以輕易繪制整個(gè)屏幕的像素成艘,但如果發(fā)生重疊像素的關(guān)系需要不停的重繪同一區(qū)域的赏半,掉幀和卡頓就有可能發(fā)生
GPU會(huì)放棄繪制那些完全被其他圖層遮擋的像素,但是要計(jì)算出一個(gè)圖層是否被遮擋也是相當(dāng)復(fù)雜并且會(huì)消耗CPU的資源淆两,同樣断箫,合并不同圖層的透明重疊元素消耗的資源也很大,所以秋冰,為了快速處理仲义,一般不要使用透明圖層,
1). 給View添加一個(gè)固定剑勾、不透明的顏色
2). 設(shè)置opaque 屬性為true
但是這對(duì)性能調(diào)優(yōu)的幫助并不大埃撵,因?yàn)閁IView的opaque 屬性默認(rèn)為true,也就是說(shuō)虽另,只要不是認(rèn)為設(shè)置成透明暂刘,都不會(huì)出現(xiàn)圖層混合
而對(duì)于UIIimageView來(lái)說(shuō),不僅需要自身需要不是透明的捂刺,它的圖片也不能含有alpha通道谣拣,這也上圖9張圖片是綠色的原因,因此圖像自身的性質(zhì)也可能會(huì)對(duì)結(jié)果有影響叠萍,所以你確定自己的代碼沒(méi)問(wèn)題芝发,還出現(xiàn)了混合圖層可能就是圖片的問(wèn)題了
而針對(duì)于屏幕中的文字高亮成紅色,是因?yàn)橐粵](méi)有給文字的label增加不透明的背景顏色苛谷,而是當(dāng)UILabel內(nèi)容為中文時(shí)辅鲸,label的實(shí)際渲染區(qū)域要大于label的size,因?yàn)橥鈬辛艘蝗Φ年幱案沟睿艜?huì)出現(xiàn)圖層混合我們需要給中文的label加上如下代碼:

        retweededTextLab?.layer.masksToBounds = true
        retweededTextLab?.backgroundColor = UIColor.groupTableViewBackground
        statusLab.layer.masksToBounds = true
        statusLab.backgroundColor = UIColor.white

看下效果圖:

圖層混合優(yōu)化.png

那些label的顏色也變成藍(lán)色的了独悴,這里有一點(diǎn)需要說(shuō)明一下,
1). statusLab.layer.masksToBounds = true 單獨(dú)使用不會(huì)出現(xiàn)離屏渲染
2). 如果對(duì)label設(shè)置了圓角的話锣尉,圓角部分會(huì)離屏渲染刻炒,離屏渲染的前提是位圖發(fā)生了形變

  • Color Hits Green and Misses Red(光柵化緩存圖層的命中情況)

這個(gè)選項(xiàng)主要是檢測(cè)我們有無(wú)濫用或正確使用layer的shouldRasterize屬性.成功被緩存的layer會(huì)標(biāo)注為綠色,沒(méi)有成功緩存的會(huì)標(biāo)注為紅色。
很多視圖Layer由于Shadow自沧、Mask和Gradient等原因渲染很高坟奥,因此UIKit提供了API用于緩存這些Layer,self.layer.shouldRasterize = true系統(tǒng)會(huì)將這些Layer緩存成Bitmap位圖供渲染使用树瞭,如果失效時(shí)便丟棄這些Bitmap重新生成。圖層Rasterization柵格化好處是對(duì)刷新率影響較小爱谁,壞處是刪格化處理后的Bitmap緩存需要占用內(nèi)存晒喷,而且當(dāng)圖層需要縮放時(shí),要對(duì)刪格化后的Bitmap做額外計(jì)算访敌。 使用這個(gè)選項(xiàng)后時(shí)凉敲,如果Rasterized的Layer失效,便會(huì)標(biāo)注為紅色寺旺,如果有效標(biāo)注為綠色爷抓。當(dāng)測(cè)試的應(yīng)用頻繁閃現(xiàn)出紅色標(biāo)注圖層時(shí),表明對(duì)圖層做的Rasterization作用不大阻塑。
在測(cè)試的過(guò)程中,第一次加載時(shí),開(kāi)啟光柵化的layer會(huì)顯示為紅色,這是很正常的,因?yàn)檫€沒(méi)有緩存成功蓝撇。但是如果在接下來(lái)的測(cè)試,。例如我們來(lái)回滾動(dòng)TableView時(shí),我們?nèi)匀话l(fā)現(xiàn)有許多紅色區(qū)域,那就需要謹(jǐn)慎對(duì)待了

  • Color Copied Image (拷貝的圖片)

這個(gè)選項(xiàng)主要檢查我們有無(wú)使用不正確圖片格式,由于手機(jī)顯示都是基于像素的叮姑,所以當(dāng)手機(jī)要顯示一張圖片的時(shí)候唉地,系統(tǒng)會(huì)幫我們對(duì)圖片進(jìn)行轉(zhuǎn)化。比如一個(gè)像素占用一個(gè)字節(jié)传透,故而RGBA則占用了4個(gè)字節(jié),則1920 x 1080的圖片占用了7.9M左右极颓,但是平時(shí)jpg或者png的圖片并沒(méi)有那么大朱盐,因?yàn)樗鼈儗?duì)圖片做了壓縮,但是是可逆的菠隆。所以此時(shí)兵琳,如果圖片的格式不正確,則系統(tǒng)將圖片轉(zhuǎn)化為像素的時(shí)間就有可能變長(zhǎng)骇径。而該選項(xiàng)就是檢測(cè)圖片的格式是否是系統(tǒng)所支持的躯肌,若是GPU不支持的色彩格式的圖片則會(huì)標(biāo)記為青色,則只能由CPU來(lái)進(jìn)行處理。CPU被強(qiáng)制生成了一些圖片破衔,然后發(fā)送到渲染服務(wù)器清女,而不是簡(jiǎn)單的指向原始圖片的的指針。我們不希望在滾動(dòng)視圖的時(shí)候,CPU實(shí)時(shí)來(lái)進(jìn)行處理,因?yàn)橛锌赡軙?huì)阻塞主線程晰筛。

  • Color Immediately (顏色立即更新)

通常 Core Animation 以每秒10此的頻率更新圖層的調(diào)試顏色嫡丙,對(duì)于某些效果來(lái)說(shuō),這可能太慢了读第,這個(gè)選項(xiàng)可以用來(lái)設(shè)置每一幀都更新(可能會(huì)影響到渲染性能曙博,所以不要一直都設(shè)置它)

  • Color Misaligned Image (圖片對(duì)齊方式)

這里會(huì)高亮那些被縮放或者拉伸以及沒(méi)有正確對(duì)齊到像素邊界的圖片,即圖片Size和imageView中的Size不匹配怜瞒,會(huì)使圖過(guò)程片縮放父泳,而縮放會(huì)占用CPU,所以在寫代碼的時(shí)候保證圖片的大小匹配好imageView,如下圖所示:
圖片尺寸 170 * 220px

        let imageView = UIImageView(frame: CGRect(x: 50, y: 100, width: 170, height: 220))
        imageView.image = UIImage(named: "cat")
        view.addSubview(imageView)

蘋果的單位以點(diǎn)計(jì)算惠窄,而 imageView的尺寸是170 * 220 pt 而圖片是 170 * 220px逝她,所以相當(dāng)于在屏幕上對(duì)圖片方法了一倍,看效果圖如下:


Color Misaligned Image.png

可以看到圖片高亮成黃色顯示睬捶,更改下imageView的大小

        let imageView = UIImageView(frame: CGRect(x: 50, y: 100, width: 85, height: 110))
        imageView.image = UIImage(named: "cat")
        view.addSubview(imageView) 

看下效果圖

Color Misaligned Image -2.png

當(dāng)imageView和image的大小一致的時(shí)候黔宛,就正常顯示了

  • Color Offscreen- Rendered Yellow (離屏渲染)

這里會(huì)把那些需要離屏渲染的到圖層高亮成黃色,而出發(fā)離屏渲染的可能有

/* 圓角處理 */
view.layer.maskToBounds = truesomeView.clipsToBounds = true
/* 設(shè)置陰影 */
view.shadow..
/* 柵格化 */
view.layer.shouldRastarize = true

針對(duì)柵格化處理擒贸,我們需要指定屏幕的分辨率

        //離屏渲染 - 異步繪制  耗電
        self.layer.drawsAsynchronously = true
        
        //柵格化 - 異步繪制之后 臀晃,會(huì)生成一張獨(dú)立的圖片 cell 在屏幕上滾動(dòng)的時(shí)候,本質(zhì)上滾動(dòng)的是這張圖片 
        //cell 優(yōu)化介劫,要盡量減少圖層的數(shù)量徽惋,想當(dāng)于只有一層
        //停止?jié)L動(dòng)之后,可以接受監(jiān)聽(tīng)
        self.layer.shouldRasterize = true
        
        //使用 “柵格化” 必須指定分辨率
        self.layer.rasterizationScale = UIScreen.main.scale

指定陰影的路徑座韵,可以防止離屏渲染

        // 指定陰影曲線险绘,防止陰影效果帶來(lái)的離屏渲染
        imageView.layer.shadowPath = UIBezierPath(rect: imageView.bounds).cgPath 

這行代碼制定了陰影路徑,如果沒(méi)有手動(dòng)指定誉碴,Core Animation會(huì)去自動(dòng)計(jì)算宦棺,這就會(huì)觸發(fā)離屏渲染。如果人為指定了陰影路徑黔帕,就可以免去計(jì)算代咸,從而避免產(chǎn)生離屏渲染。
設(shè)置cornerRadius本身并不會(huì)導(dǎo)致離屏渲染成黄,但很多時(shí)候它還需要配合layer.masksToBounds = true使用呐芥。根據(jù)之前的總結(jié),設(shè)置masksToBounds會(huì)導(dǎo)致離屏渲染奋岁。解決方案是盡可能在滑動(dòng)時(shí)避免設(shè)置圓角思瘟,如果必須設(shè)置圓角,可以使用光柵化技術(shù)將圓角緩存起來(lái):

// 設(shè)置圓角
label.layer.masksToBounds = true
label.layer.cornerRadius = 8
label.layer.shouldRasterize = true
label.layer.rasterizationScale = layer.contentsScale

如果界面中有很多控件需要設(shè)置圓角闻伶,比如tableView中滨攻,當(dāng)tableView有超過(guò)25個(gè)圓角,使用如下方法

view.layer.cornerRadius = 10
view.maskToBounds = Yes

那么fps將會(huì)下降很多虾攻,特別是對(duì)某些控件還設(shè)置了陰影效果铡买,更會(huì)加劇界面的卡頓、掉幀現(xiàn)象霎箍,對(duì)于不同的控件將采用不同的方法進(jìn)行處理:
1). 對(duì)于label類奇钞,可以通過(guò)CoreGraphics來(lái)畫出一個(gè)圓角的label
2). 對(duì)于imageView,通過(guò)CoreGraphics對(duì)繪畫出來(lái)的image進(jìn)行裁邊處理漂坏,形成一個(gè)圓角的imageView,代碼如下:

    /// 創(chuàng)建圓角圖片
    ///
    /// - parameter radius:    圓角的半徑
    /// - parameter size:      圖片的尺寸
    /// - parameter backColor: 背景顏色 默認(rèn) white
    /// - parameter lineWith:  圓角線寬 默認(rèn) 1
    /// - parameter lineColor: 線顏色 默認(rèn) darkGray
    ///
    /// - returns: image
    func yw_drawRectWithRoundCornor(radius: CGFloat, size: CGSize, backColor: UIColor = UIColor.white, lineWith: CGFloat = 1, lineColor: UIColor = UIColor.darkGray) -> UIImage? {
        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: size)
        UIGraphicsBeginImageContextWithOptions(rect.size, true, 0)
        let bezier = UIBezierPath(roundedRect: rect, byRoundingCorners: UIRectCorner.allCorners, cornerRadii: CGSize(width: radius, height: radius))
        
        backColor.setFill()
        UIRectFill(rect)
        
        bezier.addClip()
        draw(in: rect)

        bezier.lineWidth = 1
        lineColor.setStroke()
        bezier.stroke()
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result
    }
  • Color Compositing Fast-Path Blue

這個(gè)選項(xiàng)會(huì)對(duì)任何直接使用OpenGL繪制的圖層進(jìn)行高亮景埃,如果僅僅使用UIKit或者Core Animation的API媒至,不會(huì)有任何效果,恕我才疏學(xué)淺谷徙,所以拒啰,我在測(cè)試的時(shí)候,確實(shí)在屏幕上沒(méi)有任何反應(yīng)的完慧,openGL 繪制谋旦,我也不會(huì),所以屈尼,就不知道到底會(huì)有什么效果了册着,哪位大神會(huì)的話,貼段代碼脾歧,給我試試啊~~~

  • Flash Updated Regions (Core Graphics 繪制的圖層)

此選項(xiàng)會(huì)對(duì)重繪的內(nèi)容進(jìn)行高亮成黃色甲捏,也就是軟件層面使用Core Graphics 繪制的圖層。我測(cè)試的時(shí)候鞭执,好像有點(diǎn)問(wèn)題司顿,這種解釋,不知道是不是我寫代碼的問(wèn)題兄纺,所以大溜,就不多說(shuō)了

上面說(shuō)的這些高亮圖層,幾個(gè)常用的選項(xiàng)在模擬器里面可以直接調(diào)試囤热,非常方便


模擬器高亮圖層.png

紅框中的選項(xiàng)猎提,上面都有解釋,這里就不說(shuō)了旁蔼,勾選項(xiàng),打開(kāi)模擬器疙教,一看就知道了~
麻蛋棺聊、Core Animation 部分終于扯完了,扯了好多啊贞谓。限佩。。

  • Leaks

又一個(gè)灰常重要的工具裸弦,主要檢查內(nèi)存泄漏祟同,在前面Allcations里面我們提到內(nèi)存泄漏分兩種,現(xiàn)在我們研究Leaked Memory理疙, 從用戶使用角度來(lái)看晕城,內(nèi)存泄漏本身不會(huì)產(chǎn)生什么危害,作為用戶窖贤,根本感覺(jué)不到內(nèi)存泄漏的存在砖顷,真正的危害在于內(nèi)存泄漏的堆積贰锁,最終會(huì)耗盡系統(tǒng)所有的內(nèi)存。我們直接看圖:


界面的介紹

在 instruments 中,雖然選擇了 Leaks 模板,但默認(rèn)情況下也會(huì)添加 Allocations 模板.基本上凡是內(nèi)存分析都會(huì)使用 Allocations 模板, 它可以監(jiān)控內(nèi)存分布情況滤蝠。
選中 Allocations 模板3區(qū)域會(huì)顯示隨著時(shí)間的變化內(nèi)存使用的折線圖,同時(shí)在4區(qū)域會(huì)顯示內(nèi)存使用的詳細(xì)信息,以及對(duì)象分配情況.
點(diǎn)擊 Leaks 模板, 可以查看內(nèi)存泄露情況豌熄。如果在3區(qū)域有 紅X 出現(xiàn), 則有內(nèi)存泄露, 4區(qū)域則會(huì)顯示泄露的對(duì)象.
打用leaks進(jìn)行監(jiān)測(cè):點(diǎn)擊泄露對(duì)象可以在(下圖)看到它們的內(nèi)存地址, 占用字節(jié), 所屬框架和響應(yīng)方法等信息.打開(kāi)擴(kuò)展視圖, 可以看到右邊的跟蹤堆棧信息,4 黑色代碼最有可能出現(xiàn)內(nèi)存泄漏的方法


監(jiān)測(cè)結(jié)果的分析物咳,


Time Profiler

在開(kāi)發(fā)的過(guò)程中锣险,我們經(jīng)常能感覺(jué)到,點(diǎn)擊某一按鈕览闰,或者做了某一操作芯肤,有卡頓,這就是延遲焕济,那使用此工具纷妆,就可以揪出耗時(shí)的函數(shù),先看一下晴弃,調(diào)試界面介紹:

time Profiler.png

根據(jù)查看的相關(guān)耗時(shí)操作掩幢,我們就可以右鍵定位當(dāng)耗時(shí)的方法:
寫一個(gè)簡(jiǎn)單例子看一下:

屏幕快照 2016-10-30 下午4.23.02.png

看上圖,可以很清楚看到此方法耗時(shí)比較嚴(yán)重上鞠,右鍵打開(kāi)定位到此方法的代碼:

屏幕快照 2016-10-30 下午4.24.57.png

代碼截圖如下:


屏幕快照 2016-10-30 下午4.25.06.png

這時(shí)候际邻,我們把循環(huán)放到子線程來(lái)做

    @IBAction func btnAction(_ sender: AnyObject) {
        let svc = SecondViewController()
        svc.title = "第二個(gè)頁(yè)面"
        //全局隊(duì)列異步執(zhí)行
        DispatchQueue.global().async {
            for i in 0..<8888 {
                print(i)
            }
        }
        navigationController?.pushViewController(svc, animated: true)
    } ```

看效果圖:

![屏幕快照 2016-10-30 下午4.33.43.png](http://upload-images.jianshu.io/upload_images/2240549-29192d461798e858.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

到這里比較重要Instrument調(diào)試工具介紹的差不多了,說(shuō)一個(gè)Xcode8.0新出的功能芍阎,很好用也很重要的功能:

![屏幕快照 2016-10-30 下午4.40.08.png](http://upload-images.jianshu.io/upload_images/2240549-95af00e9cc66fd1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

還是以例子說(shuō)說(shuō)吧世曾,Viewcontroller里面一個(gè)button,點(diǎn)擊跳到SecondViewcontroller谴咸,SecondViewcontroller里面有個(gè)View轮听,view里面有個(gè)button,button點(diǎn)擊回到ViewController,實(shí)現(xiàn)是通過(guò)view的屬性拿到SecondviewConroller的引用岭佳,pop回去
子view的代碼如下:

class SubView: UIView {
var delegate: SecondViewController?
@IBAction func brnAction(_ sender: AnyObject) {
delegate?.navigationController!.popViewController(animated: true)
}
}

當(dāng)我們從第二個(gè)控制器血巍,回到第一個(gè)控制器的時(shí)候,我們點(diǎn)一下珊随,剛那個(gè)按鈕述寡,看圖:
![屏幕快照 2016-10-30 下午4.47.53.png](http://upload-images.jianshu.io/upload_images/2240549-26cdf4b29bcfccab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

第二個(gè)控制器和子View都內(nèi)存中,我們很容易叶洞,就可以發(fā)現(xiàn)問(wèn)題了鲫凶,這是因?yàn)椋琒econdViewController強(qiáng)引用了SubView衩辟,而我們SubView也強(qiáng)引用了SecondViewcontroller螟炫,就造成相互強(qiáng)引用,引用計(jì)數(shù)器不能為0惭婿,不能銷毀了不恭,我們只要把屬性前面加個(gè)weak叶雹,變成弱引用就可以了

weak var delegate: SecondViewController?
@IBAction func brnAction(_ sender: AnyObject) {
delegate?.navigationController!.popViewController(animated: true)
}

這時(shí)候,我們從第二個(gè)控制器pop回來(lái)的時(shí)候换吧,看下內(nèi)存:
![屏幕快照 2016-10-30 下午4.54.06.png](http://upload-images.jianshu.io/upload_images/2240549-b6d98af07c69aef4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
現(xiàn)在就沒(méi)問(wèn)題了折晦,怎樣這個(gè)工具是不是挺好用啊

還有一些針對(duì)TableView,collectionView的優(yōu)化沾瓦,有空再聊吧满着,
* 聲明:
1.本文有些文字描述,來(lái)自于其他博客和文章贯莺,因?yàn)橛X(jué)的描述挺好(好吧我承認(rèn)风喇、自己也寫不出來(lái)),所以就拿來(lái)用了缕探,若有不妥的地方魂莫,請(qǐng)告知我,我會(huì)立即刪除修改
2.因?yàn)楸救说乃接邢薜模赡苡袑懙牟粚?duì)的地方耙考,歡迎各位大大多指點(diǎn)、不勝感激
*****
最后的最后:碼字不易潭兽,如果對(duì)你有用倦始,點(diǎn)個(gè)喜歡唄!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末山卦,一起剝皮案震驚了整個(gè)濱河市鞋邑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌账蓉,老刑警劉巖枚碗,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異铸本,居然都是意外死亡视译,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門归敬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人鄙早,你說(shuō)我怎么就攤上這事汪茧。” “怎么了限番?”我有些...
    開(kāi)封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵舱污,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我弥虐,道長(zhǎng)扩灯,這世上最難降的妖魔是什么媚赖? 我笑而不...
    開(kāi)封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮珠插,結(jié)果婚禮上惧磺,老公的妹妹穿的比我還像新娘。我一直安慰自己捻撑,他們只是感情好磨隘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著顾患,像睡著了一般番捂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上江解,一...
    開(kāi)封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天设预,我揣著相機(jī)與錄音,去河邊找鬼犁河。 笑死鳖枕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呼股。 我是一名探鬼主播耕魄,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼彭谁!你這毒婦竟也來(lái)了吸奴?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缠局,失蹤者是張志新(化名)和其女友劉穎则奥,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體狭园,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡读处,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了唱矛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罚舱。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绎谦,靈堂內(nèi)的尸體忽然破棺而出管闷,到底是詐尸還是另有隱情,我是刑警寧澤窃肠,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布包个,位于F島的核電站,受9級(jí)特大地震影響冤留,放射性物質(zhì)發(fā)生泄漏碧囊。R本人自食惡果不足惜树灶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糯而。 院中可真熱鬧天通,春花似錦、人聲如沸歧蒋。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谜洽。三九已至萝映,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間阐虚,已是汗流浹背序臂。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留实束,地道東北人奥秆。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像咸灿,于是被迫代替她去往敵國(guó)和親构订。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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