日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

app 性能优化的那些事(二)

發(fā)布時(shí)間:2025/3/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 app 性能优化的那些事(二) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

來源:樹下的老男孩?

鏈接:http://www.jianshu.com/p/2a01e5e2141f

?

這次我們來說說iOS app中滑動(dòng)的那些事。iOS為了提高滑動(dòng)的流暢感,特意在滑動(dòng)的時(shí)候?qū)unloop模式切換到UITrackingRunLoopMode,在這個(gè)過程中專心做跟滑動(dòng)相關(guān)的工作,這也就是在滑動(dòng)過程中為什么nstimer無法工作的原因,因?yàn)閮蓚€(gè)沒在同一mode下面。但我們可能經(jīng)常會(huì)遇到滑動(dòng)不怎么流暢的情況,比如在項(xiàng)目中碰到在滑動(dòng)tableview的時(shí)候不怎么順暢,感覺有點(diǎn)不爽,即便是在測(cè)試中表現(xiàn)最好的5s(touch之類的感受更直觀)。

?

    tableview 滑動(dòng)不流暢

那碰到這種情況該怎么處理,分析圖像動(dòng)畫性能主要用的是Core Animation這個(gè)組件,先簡(jiǎn)單介紹一下里面一些經(jīng)常用到的選項(xiàng):

?

  • Color Blended layers

    標(biāo)示混合的圖層會(huì)為紅色,不透明的圖層為綠色,通常我們希望綠色的區(qū)域越多越好。

  • Color Hits Green and Misses Red

    假如我們?cè)O(shè)置viewlayer的shouldRasterize為YES,那些成功被緩存的layer會(huì)標(biāo)注為綠色,反之為紅色,下面會(huì)有詳細(xì)介紹。

  • Color copied images

    標(biāo)示那些被Core Animation拷貝的圖片。這主要是因?yàn)樵搱D片的色彩格式不能被GPU直接處理,需要在CPU這邊做轉(zhuǎn)換,假如在主線層做這個(gè)操作對(duì)性能會(huì)有一定的影響。

  • Color misaligned images

    被縮放的圖片會(huì)被標(biāo)記為黃色,像素不對(duì)齊則會(huì)標(biāo)注為紫色。

  • Color offscreen-rendered yellow

    標(biāo)示哪些layer需要做離屏渲染(offscreen-render)。

?


?

簡(jiǎn)單介紹完Core Animation的一些東西之后我們回過頭來看看哪些問題會(huì)影響到圖形的性能,下面這張圖摘自WWDC2014(Advanced Graphics and Animations for iOS Apps,這上面的一些分享非常有技術(shù)性)

?

      performance investigation mindset.png

當(dāng)你碰到性能問題的時(shí)候,你可以思考一下:

?

是否受到CPU或者GPU的限制?

是否有不必要的CPU渲染?

是否有太多的離屏渲染操作?

是否有太多的圖層混合操作?

是否有奇怪的圖片格式或者尺寸?

是否涉及到昂貴的view或者效果?

view的層次結(jié)構(gòu)是否合理?

?

那么哪些是你最該開始考慮的方向呢?通常發(fā)生圖形性能問題的時(shí)候,比如列表滑動(dòng)不順暢、動(dòng)畫卡頓等,大部分都是由于Offscreen Rendering(離屏渲染)或者blending導(dǎo)致的,因?yàn)檫@在動(dòng)畫的每一幀都會(huì)涉及到。

?

offscreen-render

?

什么是offscreen-render?offscreen-render涉及的內(nèi)容比較多,有offscreen-render那就有onscreen render,onscreen render指的是GPU在當(dāng)前用于顯示的屏幕緩沖區(qū)進(jìn)行渲染,相反offscreen-render就是不在當(dāng)前的屏幕緩存區(qū),而在另外的緩沖區(qū)進(jìn)行渲染,offscreen-render有兩種形式:

?

CPU的offscreen-render

?

使用CPU來完成渲染操縱,通常在你使用:

?

  • drawRect (如果沒有自定義繪制的任務(wù)就不要在子類中寫一個(gè)空的drawRect方法,因?yàn)橹灰獙?shí)現(xiàn)了該方法,就會(huì)為視圖分配一個(gè)寄宿圖,這個(gè)寄宿圖的像素尺寸等于視圖大小乘以 contentsScale的值,造成資源浪費(fèi))

  • 使用Core Graphics

    上面的兩種情況使用的就是CPU離屏渲染,首先分配一塊內(nèi)存,然后進(jìn)行渲染操作生成一份bitmap位圖,整個(gè)渲染過程會(huì)在你的應(yīng)用中同步的進(jìn)行,接著再將位圖打包發(fā)送到iOS里一個(gè)單獨(dú)的進(jìn)程–render server,理想情況下,render server將內(nèi)容交給GPU直接顯示到屏幕上。

?

GPU的offscreen-render

?

使用GPU在當(dāng)前屏幕緩沖區(qū)以外開辟一個(gè)新的緩沖區(qū)進(jìn)行繪制,通常發(fā)生的情況有:

?

  • 設(shè)置cornerRadius, masks, shadows,edge antialiasing等

  • 設(shè)置layer.shouldRasterize = YES

    ?

                    渲染流程

offscreen-render對(duì)性能到底有什么影響?通常大家說的離屏渲染指的是GPU這塊(當(dāng)然CPU這塊也會(huì)有影響,也需要消耗一定的資源),比如修改了layer的陰影或者圓角,GPU需要做額外的渲染操作。通常GPU在做渲染的時(shí)候是很快的,但是涉及到offscreen-render的時(shí)候情況就可能有些不同,因?yàn)樾枰~外開辟一個(gè)新的緩沖區(qū)進(jìn)行渲染,然后繪制到當(dāng)前屏幕的過程需要做onscreen跟offscreen上下文之間的切換,這個(gè)過程的消耗會(huì)比較昂貴,涉及到OpenGL的pipeline跟barrier,而且offscreen-render在每一幀都會(huì)涉及到,因此處理不當(dāng)肯定會(huì)對(duì)性能產(chǎn)生一定的影響,所以可以的話盡量減少offscreen-render的圖層,查看哪些圖層需要離屏渲染可以用Instruments的Core Animation工具進(jìn)行檢測(cè),Color Offscreen-Rendered Yellow選項(xiàng)會(huì)將對(duì)應(yīng)的圖層標(biāo)記為黃色。

?

Blending

?

假如最上層的view是不透明的,那直接使用這個(gè)view的對(duì)應(yīng)顏色之就可以,但如果view是透明的,在計(jì)算像素的顏色值時(shí)就需要計(jì)算它下面圖層,透明的視圖越多,計(jì)算量就越大,因此也會(huì)對(duì)圖形的性能產(chǎn)生一定的影響,所以可以的話也盡量減少透明圖層的數(shù)目。

?

Demo

?

下面給出一個(gè)簡(jiǎn)單demo(https://github.com/FreeMind-LJ/OptimiseDemo)的優(yōu)化過程,這個(gè)demo里面涉及到的問題是在實(shí)際項(xiàng)目中所碰到的,也就是最上面那張圖里列表滑動(dòng)不流暢情況—由陰影以及圓角導(dǎo)致的offscreen-render。

整個(gè)頁(yè)面就是一個(gè)簡(jiǎn)單的tableview,其中頭像為圓角,一個(gè)label有陰影效果,滑動(dòng)的時(shí)候在iPod上幀率只有可憐的28FPS。

?

Color Offscreen-Rendered Yellow

28FPS.png

其中黃色的區(qū)域就是離屏渲染的地方,也就是含有圓角跟陰影的layer。

?

shadowPath

?

設(shè)置label的陰影效果可以通過:

?

cell.sign.layer.shadowOffset = CGSizeMake(0, 2);

????cell.sign.layer.shadowOpacity = 0.5;

????cell.sign.layer.shadowColor = [UIColor blackColor].CGColor;

?

但是你可以發(fā)現(xiàn)這會(huì)導(dǎo)致離屏渲染,一個(gè)簡(jiǎn)單的不需要離屏渲染的方法就是制定陰影的路徑,也就是設(shè)置layer的shadowPath屬性,通過instruments發(fā)現(xiàn)陰影的地方?jīng)]有黃色了,幀率也提高到了40FPS:

?

cell.sign.layer.shadowPath = [UIBezierPath??bezierPathWithRect:cell.sign.bounds].CGPath;

?

設(shè)置shadowPath消除離屏渲染.png

?

rasterize

?

對(duì)于圓角這種類似導(dǎo)致的性能問題,最簡(jiǎn)單的就是在列表中不要使用圓角,假如要使用圓角的話,一種最快提升性能的方式就是設(shè)置layer的shouldRasterize為YES:

?

cell.layer.shouldRasterize = YES;

????cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

?

雖然被Rasterize的圖層也會(huì)引起離屏渲染,如下圖所示,整個(gè)cell都被標(biāo)示為黃色:

?

shouldRasterize.png

layer設(shè)置shouldRasterize=YES之后,會(huì)把被光柵化的圖層保存成位圖并緩存起來,其中圓角或者陰影之類的效果也是直接保存到位圖當(dāng)中,當(dāng)需要渲染到屏幕上的時(shí)候只需要到緩存中去取對(duì)應(yīng)的位圖進(jìn)行顯示就行了,加快了整個(gè)渲染過程。可以通過勾選instruments core animation中的Color Hits Green and Misses Red選項(xiàng)來查看圖層是否被緩存了,如果圖層顯示為綠色則表示已經(jīng)被緩存起來了,也就是這個(gè)緩沖區(qū)的內(nèi)容被復(fù)用了,不用在去重新創(chuàng)建緩沖區(qū),反之則是用紅色標(biāo)示。如下圖可以看到設(shè)置shouldRasterize之后,cell都被標(biāo)示為綠色了,如果滑動(dòng)過程中發(fā)現(xiàn)都是紅色的證明就有問題了:

?

cached.png

再看看現(xiàn)在滑動(dòng)的幀率:

優(yōu)化后.png

可以發(fā)現(xiàn)現(xiàn)在滾動(dòng)的性能大大提高了,光柵化對(duì)于那些有很多子view嵌套在一起、view的層級(jí)復(fù)雜或者有很復(fù)雜特效效果的圖層有很明顯的提升,因?yàn)檫@些內(nèi)容都被緩存到位圖當(dāng)中了。但是使用光柵化需要注意一些內(nèi)容:

?

  • 適用于內(nèi)容基本不變的圖層

    假如圖層的內(nèi)容經(jīng)常變化,比如cell里面有涉及到動(dòng)畫之類的,那么緩存的內(nèi)容就無效了,GPU需要重新創(chuàng)建緩存區(qū),導(dǎo)致離屏渲染,這又涉及到OpenGL的上下文環(huán)境切換,反而降低性能。

  • 不要過度使用

    緩存區(qū)的大小被設(shè)置為屏幕大小的2.5倍,假如過分使用同樣會(huì)導(dǎo)致大量的離屏渲染。

  • 如果緩存的內(nèi)容超過100ms沒有被使用則會(huì)被回收。

?


?

tips

?

  • 對(duì)于圓角可以使用一張中間圓形透明的圖覆蓋在上面,雖然這會(huì)引入blending操作,但是大部分情況下性能會(huì)比離屏渲染好。

  • 讓你的view層次結(jié)構(gòu)平坦一些,因?yàn)镺penGL在渲染layer的時(shí)候,在碰到有子層級(jí)layer的時(shí)候可能需要停下來把兩者合成到一個(gè)buffer里再接著渲染。(When the OpenGL renderer goes to draw each layer, it may have to stop for some subhierarchies and composite them into a single buffer).

  • 延遲加載圖片

    有時(shí)候在邊滾動(dòng)邊設(shè)置圖片的時(shí)候可能會(huì)有一定的影響,因此可以在滾動(dòng)的時(shí)候imageview不執(zhí)行setimage的操作,滾動(dòng)停止的時(shí)候才加載圖片,由于滾動(dòng)的時(shí)候NSRunloop是處于UITrackingRunLoopMode模式下,可以采用如下的方式,將設(shè)置圖片放到NSDefaultRunLoopMode模式下才進(jìn)行:

?

UIImage *downloadedImage = ...;

??[self.avatarImageView performSelector:@selector(setImage:)

???????????????????????????? withObject:downloadedImage

???????????????????????????? afterDelay:0

????????????????????????????????inModes:@[NSDefaultRunLoopMode]];

?

  • 圖片加載的極限優(yōu)化方式:FastImageCache

    https://github.com/path/FastImageCache

?


?

圖形性能這塊有什么好的想法也可提出來交流一下~~

?

參考:

?

  • https://lobste.rs/s/ckm4uw/a_performance-minded_take_on_ios_design/comments/itdkfh

  • Advanced Graphics and Animations for iOS Apps

  • http://iosinjordan.tumblr.com/post/56778173518/help-my-tables-dont-scroll-smoothly

    ?

?

轉(zhuǎn)載于:https://www.cnblogs.com/fengmin/p/5937316.html

總結(jié)

以上是生活随笔為你收集整理的app 性能优化的那些事(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。