登录 当即注册
金钱:

Code4App-188bet注册-iOS 开源代码库-188bet官网实例查找-iOS特效示例-188bet官网比方下载-Code4App.com

iOS功用优化系列篇之“列表流通度优化” [仿制链接]

2019-5-28 14:12
iOS葡萄 阅览:107 谈论:0 赞:0
Tag:  

原文作者:Hello_Vincent
原文地址:https://juejin.im/post/5b72aaf46fb9a009764bbb6a#heading-1

这一篇文章是iOS功用优化系列文章的的第二篇,首要内容是关于列表流通度的优化。在具体内容的论述进程中会结合功用优化的全体准则进行论述,所以主张咱们在阅览这篇文章前先阅览一下上一篇文章:iOS功用优化系列篇之“优化全体准则”

因为平常作业比较忙,两篇之间的距离有点久。但这两篇文章出乎我预料地受到了咱们的喜爱,所以我期望后边有时间能把这个系列更新下去,下一步预备写一篇关于iOS内存相关的优化文章。也期望这篇列表流通度优化的文章能够给咱们带来一点点启示。

和上一篇总述性质的文章不同,这一篇文章工程实用性更强一些,更多的是一些优化技能细节。文中谈论了许多或许影响列表流通度的要素,因为2018 WWDC里边叙述了许多的关于功用优化相关的内容,因而本文也在相关的内容里边参加2018 WWDC的功用优化部分。

读者可将本体提及的优化手法或许原理运用到自己的项目中去。可是期望咱们在优化进程中,要结合自己的项目具体问题具体分析,因为本文谈论的影响流通度的要素,或许并不是你的运用流通性欠安的瓶颈,依据我的阅历,大部分流通的问题都是事务逻辑导致的,反倒什么离屏烘托啊之类咱们耳熟能详的流通度的影响要素在实践项目中并没有幻想的那么大。假如不经实地丈量就盲目运用一些优化手法,或许会导致过度优化,得不偿失。

卡顿发生的原因

在全体准则篇中说到,五大准则中的其间一个便是要了解优化使命的底层运转机制,因为只需深化了解底层机制才干更好的有针对性的提出更优的处理方案,所以在进行列表流通度优化前,咱们必定要弄清楚一个view从创立到显现到屏幕上都阅历了那些进程,在这些进程中那些方面或许会导致功用瓶颈,以及形成卡顿的底层原因是什么。

咱们知道iOS设备大部分状况下,屏幕改写频率是60hz(ProMotion下是120hz),也便是每隔16.67ms会进行一次屏幕改写。每次改写时,需求CPU和GPU协作完结一次图画显现。其首要流程如下:

运用内:

  • 布局。CPU创立view,设置其特色(frame、background color等等)

  • 创立backing images。setContents将一个image传給layer或许经过 drawRect:或 drawLayer:inContext制作

  • 预备。Core Animation将layer发送到render server前的一些预备作业,比方图片解码等。

  • 提交。Core animation将layers打包经过 IPC (Inter-Process Communication) 发送到render server

运用外(render server):

  • 设置用来烘托的OpenGL triangles(假如是有动画,还需核算动画layer的特色的中心值)。

  • 烘托这些可见的triangles,将成果提交到视频缓冲区

  • 视频操控器以60hz频率读取缓冲区内容显现到显现器,假如在16.67ms内没有完结提交,则会被丢掉。

从上面的图中能够看到,在view显现的进程中,CPU和GPU都各自承当了不同的使命,CPU和GPU不管哪个阻止了显现流程,都会形成掉帧现象。所以优化办法也需求别离对CPU和GPU压力进行评价和优化,在CPU和GPU压力之间找到功用最优的平衡点, 不管过度优化哪一方导致另一方压力过大都会形成全体FPS功用的下降。而寻觅平衡点的进程则因项目特色不同而不同,并没有一套通用的办法,需求咱们用instrument等功用评测东西,依据实践app的功用衡量成果去做优化,不能随便乱猜。

CPU优化

咱们先看table view在滑动进程中CPU占用的状况。

从上图能够看出,在滑动进程中CPU占用特色是:

  • 滑动时CPU占用率高、闲暇时CPU占用率底

  • 主线程CPU占用高、子线程CPU占底

依据上述特色咱们能够做如下优化:

预加载,空间换时间

为什么要预加载:

  • 滑动时CPU占用过高,16.67ms内无法完结内容提交—>导致卡顿

  • 滑动时CPU占用率高,但闲暇时CPU占用率底—>CPU占用散布特色

  • 运用CPU闲暇时间预加载,下降滑动时CPU占用峰值—>处理卡顿

经过预加载咱们期望到达的CPU抱负占用效果如下:

预加载内容:

静态资源预加载

  • 怎么预加载:创立列表前找机遇加载。如启动时、viewDidLoad、runloop闲暇时等等

  • 加载内容:缓存在磁盘的网络数据、图片、其他滑动时需求的耗时的资源

  • 留意事项:在预加载带来的滑动功用进步和内存占用添加之间权衡

动态资源预加载

  • 怎么预加载:

    • 在iOS10今后,UITableView和UICollectionView供给了预加载机制,iOS12开端prefeatching做了优化,不再与cell的加载一同并发进行,而是cell加载完结之后串行开端prefeatch,然后优化了流通度

    • iOS10曾经,也能够自己完结相似机制,首要运用的机制有:

      • UIScrollViewDelegate 供给滑动开端、完毕、速度机遇回调

      • indexPathsForRowsInRect 和layoutAttributesForElementsInRect 供给预加载的indexPath

      • 可依据滑动速度动态调整加载的量

  • 加载内容:

    • Cell的高度、subView的布局核算

    • 拉取网络数据

    • 网络图片

    • 其他耗时的资源

  • 留意事项:

    • 在预加载带来的滑动功用进步和内存占用添加之间权衡

    • 留意数据过期的问题

WWDC 2018中讲到了一个iOS12的底层优化点,苹果工程师在功用调优的时分发现一个导致丢帧的古怪case,在没有其他后台线程运转、只需滑动的状况下,会比有少数的后台线程的状况更简单掉帧。经过调研CPU的调度算法发现,在仅有滑动的状况下,为了省电,CPU占用会坚持比较底,可是这样CPU会花更多的时间来核算,就会导致或许错失这一帧。所以iOS12中,会把UIKit框架上一切的信息(滑动信息以及滑动frame的要害时间点)传递给底层CPU功用操控器,这样CPU能够更智能调度以在frame截止的机遇内完结CPU核算。这部分归于体系底层的优化,关于运用开发者只需运用运转在iOS12就能够取得这部分优化。

多线程

为什么要多线程:

  • UIKit 大部分API只能在主线程调用, 特别是一些耗时的操作,如view的创立,布局和烘托默许都是在主线程上完结

  • 主线程使命过多,16.67ms内无法完结,导致卡顿

  • 将非主线程有必要的使命,移到子线程中,减轻主线程担负

  • 多核处理器,多线程能够发挥多核并发优势,进步功用

终究经过多线程,咱们期望CPU占用到达如下效果:

运用多线程留意事项:

  • 主线程最大程度上削减非主线程有必要的使命

  • 操控子线程数量在合理的范围内,防止线程爆破,必定要依据项目实践CPU占用特色,有针对的运用多线程。

可在子线程中进行的使命

  • 图片解码

  • 文本烘托,UILabel和UITextview都是在主线程烘托的,当显现许多文本时,CPU的压力会非常大。特别是关于一些资讯类运用,这部分耗时相当大,对流通度的影响也非常显着。对此能够自定义文本控件,用TextKit或最底层的CoreText对文本异步制作。尽管这完结起来非常费事,但其带来的优势也非常大,CoreText方针创立好后,能直接获取文本的宽高级信息,防止了屡次核算(调整 UILabel 巨细时算一遍、UILabel 制作时内部再算一遍);CoreText方针占用内存较少,能够缓存下来以备稍后屡次烘托。用 [NSAttributedString boundingRectWithSize:options:context:] 来核算文本宽高,用 -[NSAttributedString drawWithRect:options:context:] 来制作文本。尽管这两个办法功用不错,但依旧需求放到后台线程进行以防止堵塞主线程。

  • UIView的drawRect, 因为 CoreGraphic 办法一般都是线程安全的,所以图画的制作能够很简单的放到后台线程进行

  • 耗时的事务逻辑

缓存

缓存的内容能够是

  • UIView。 view的创立价值很大,一些能够复用的view能够cache。例如UITableView为咱们完结的了cell的复用。

  • 图片。 图片触及磁盘IO和解码,非常耗时,能够考虑缓存。

  • 布局。其实不只仅是cell的高度能够缓存,假如cell里边有许多的文字图片等杂乱元素,cell的subView的布局也能够在第一次核算好,用Model的key来缓存。防止频频屡次的调整布局特色。在滑动列表(UITableView和UICollectionView)中激烈不主张运用Autolayout。跟着视图数量的增加,Autolayout带来的 CPU 耗费会呈指数级上升。具体数据能够看这个文章:pilky.me/36/。在WWDC20…

  • 数据, 网络拉取的数据或许db中的数据

  • 其他创立耗时,可重复运用的资源。 如NSDateFormatter等

更优的完结办法

这儿说的更优的完结办法,首要是指为了完结同一功用或许效果,CPU占用更小的完结办法。这部分包含的内容其实非常多,也很杂。受限于篇幅和水平有限,这儿笔者仅罗列一些比较常见的点,并针对其间比较重要的drawRect优化和图片优化内容做进一步的解说。

  • drawRect优化

  • 图片优化

  • 算法的时间杂乱度优化。咱们知道算法的时间杂乱 O(1) < O(log n) < O (n) < O(n^2)... 咱们或许觉得188bet注册进程中运用的算法并不多,算法对功用影响并不显着。其实不然,举iOS中的一个比方:IGListDiff选用空间换时间的办法,使得比较的算法杂乱度从 O(n^2) 变成 O(n)。IGListKit-diff-完结简析 。还比方不同容器的挑选,会带来不同的查找、刺进、删去的时间杂乱度,在大的数据量下也会带来不同的功用体现。

  • storyboard VS 代码创立view

  • frame VS autolayout autolayout功用衡量iOS12优化了autolayout的功用,耗时由指数变为线性耗时

  • UIView VS CAlayer 后者更轻量,在不需求处理接触事情的场景能够考虑运用CAlayer。UIView层级太多,会导致创立、布局等较耗时,能够尽量扁平化,乃至能够异步在子线程画到一个Image上。

  • UIImageView animationImages VS CAAnimation

  • NSDateFormatter dateFromString VS NSDate dateWithTimeIntervalSince1970:

  • 更优的事务逻辑。咱们平常在功用优化的时分,现已要优先去排查事务逻辑这块,细心收拾。个人阅历许多功用问题都是由不合理的事务逻辑导致的。运用Instruments的time profiler东西细心观察耗时的事务逻辑,做好收拾和优化作业。

  • 其他

下面具体讲下drawRect优化和图片优化

drawRect优化

  • 首选运用CAShapeLayer代替drawRect,在大多数场景下,都能够运用CAShapeLayer代替drawRect。二者比照:

    • CAShapeLayer运用GPU硬件加速,更快。GPU对高度并行的浮点运算做了优化。而drawRect运用CPU绘图,比较之下会很慢,并且非常耗CPU

    • CAShapeLayer占用内存更少。因为不会创立寄宿图,因而不管多大都不会占用太多内存。而drawRect图层每次重绘的时分都需求从头抹掉内存然后从头分配,非常占用内存。详见内存恶鬼drawRect

    • CAShapeLayer不会被图层鸿沟取舍掉

    • CAShapeLayer不会呈现像素化,经过矢量图制作而不是bitmap

    • CAShapeLayer有许多特色能够便利的做动画,比方运用strokeStart和strokeEnd能够做出了很漂亮的动画

  • 异步制作。能够运用异步制作的办法,在子线程制作好取得image,然后交给主线程。

  • Dirty Rectangles: 能够运用setNeedsDisplayInRect符号Dirty Rectangles,仅重绘指定区域,也会极大进步功用。

图片优化

在大多数app中,图片肯定是运用最频频的资源之一,咱们知道磁盘和网络的加载速度和内存比要慢许多,而一般图片都比较大,I/O非常耗时。并且图片还触及解码,也是一项非常耗费CPU的作业,因而图片的优化对app的功用有着非常要害的效果。谈谈iOS中图片的解压缩

在之前将的优化全体准则的时分,咱们说过需求了解优化方针的运转机制,咱们先了解下图片显现原理:

  • 从磁盘或许网络加载一张图片,此刻图片未解码

  • 图片赋值给UIImageView

  • 在主线程中解码,非常耗时的 CPU 操作

  • CATransaction捕捉到layer tree的改动

  • 在main run loop, 提交transaction:

    • 假如图片数据没对齐,Core Animation会仿制一份数据,进行字节对齐

    • GPU处理位图数据,进行烘托

针对上面的进程,咱们的优化手法首要有:

  • 异步下载/读取图片,这样能够防止这项非常耗时的操作堵塞主线程。

  • 预处理图片巨细。假如UIImage巨细和UIImageview的size不同的话,CPU需求提早预处理,这是一项非常耗费CPU的作业,特别是在一些缩略图的场景下,假如运用了非常大的图片,不只会带来很大的CPU功用问题,还会导致内存问题。咱们能够用instruments Core Animation 的Misaligned Image debug选项来发现此问题。这儿能够运用ImageIO中的CGImageSourceCreateThumbnailAtIndex等相关办法进行后台异步downsample,能够在CPU和内存上取得很好的功用。

  • UIImageView frame取整。视图或图片的点数(point),不能换算成整数的像素值(pixel),导致显现视图的时分需求对没对齐的边际进行额定混合核算,影响功用。凭借ceilf()、floorf()、CGRectIntegral()等将小数点后数据除掉即可。咱们能够用instruments Core Animation 的Misaligned Image debug选项来发现此问题

  • 运用mmap,防止mmcpy。解码图片 iOS从磁盘加载一张图片,运用UIImageVIew显现在屏幕上,需求经过以下进程:从磁盘仿制数据到内核缓冲区、从内核缓冲区仿制数据到用户空间。运用mmap内存映射,省去了上述第2步数据从内核空间仿制到用户空间的操作,具体能够参阅FastImageCache的完结

  • 子线程解码。假如咱们运用imgView.image = img; 假如图片没有解码,则会在主线程进行解码等操作,会极大影响滑动的流通性。

  • 字节对齐,假如数据没有字节对齐,Core Animation会再仿制一份数据,进行字节对齐,也是非常耗费CPU。

  • iOS 12引进了Automatic Backing Store这项技能。经过在确保色彩不失真的基础上,运用更少的数据量,去表达一个像素的色彩。在UIView.draw()、UIGraphicsImageRenderer、UIGraphicsImageRenderer.Range中是默许敞开的。其实咱们自己能够针对图片的特色,选用更少的byte来标明一个像素占用的空间,FastImageCache便是运用这种优化手法,有爱好的读者能够去了解一下。

  • 咱们日常开发中能够运用一些比较经典的图片缓存库,比方SDWebImage、 FastImageCache、YYImage等。这些第三方库替咱们完结的大部分优化的作业,并且接口也非常友爱。咱们可也运用这些第三方库协助咱们取得更好的功用体会。

GPU优化

CPU和GPU之所以大不相同,是因为其规划方针的不同,它们别离针对了两种不同的运用场景。CPU需求很强的通用性来处理各种不同的数据类型,一同又要逻辑判别又会引进许多的分支跳转和中止的处理。这些都使得CPU的内部结构反常杂乱。而GPU面临的则是类型高度一致的、相互无依靠的大规模数据和不需求被打断的纯洁的核算环境。所以CPU拿手逻辑操控,串行的运算。和通用类型数据运算不同,GPU拿手的是大规模并发核算,这也正是暗码破解等所需求的。所以GPU除了图画处理,也越来越多的参加到核算傍边来。参阅

iOS中GPU在显现方面的作业首要是:接纳提交的纹路(Texture)和极点描绘(三角形),进行改换(transform)、混兼并烘托,然后输出到屏幕上。屏幕上的内容,首要也便是纹路(图片)和形状(三角模仿的矢量图形)两类。一般来说,CALayer的大多数特色都是运用GPU来制作的。尽管GPU在处理图画等烘托是速度很快,但假如开发进程中运用不当,仍会导致GPU占用过高,烘托速度跟不上屏幕改写导致卡顿。

对GPU耗费比较高的操作有:

  • 纹路的烘托

    一切的 Bitmap,包含图片、文本、栅格化的内容,终究都要由内存提交到显存,绑定为 GPU Texture。不管是提交到显存的进程,仍是 GPU 调整和烘托 Texture 的进程,都要耗费不少 GPU 资源。当在较短时间显现许多图片时(比方 TableView 存在非常多的图片并且快速滑动时),CPU 占用率很低,GPU 占用非常高,界面依然会掉帧。防止这种状况的办法只能是尽量削减在短时间内**许多图片**的显现,尽或许将多张图片组成为一张进行显现。
    
    当**图片过大**,超越 GPU 的**最大纹路尺度**时,图片需求先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额定的资源耗费。现在来说,iPhone 4S 以上机型,纹路尺度上限都是 4096x4096,更具体的材料能够看这儿:[iosres.com](https://link.juejin.im?target=http%3A%2F%2Fiosres.com)。所以,尽量不要让图片和视图的巨细超越这个值。
    
  • 视图的混合 (Composing)

    当多个视图(或许说 CALayer)堆叠在一同显现时,GPU 会首先把他们混合到一同。假如视图结构过于杂乱,混合的进程也会耗费许多 GPU 资源。为了减轻这种状况的 GPU 耗费,运用应当尽量削减视图数量和层次,并在不通明的视图里标明 opaque 特色以防止无用的 Alpha 通道组成。当然,这也能够用上面的办法,把多个视图预先烘托为一张图片来显现。
    
  • 图形的生成

    CALayer 的 border、圆角、暗影、遮罩(mask),CASharpLayer 的矢量图形显现,一般会触发离屏烘托(offscreen rendering),而离屏烘托一般发生在 GPU 中。当一个列表视图中呈现许多圆角的 CALayer,并且快速滑动时,能够观察到 GPU 资源现已占满,而 CPU 资源耗费很少。这时界面依然能正常滑动,但均匀帧数会降到很低。为了防止这种状况,能够测验敞开 CALayer.shouldRasterize 特色,但这会把本来离屏烘托的操作转嫁到 CPU 上去。关于只需求圆角的某些场合,也能够用一张现已制作好的圆角图片掩盖到本来视图上面来模仿相同的视觉效果。最完全的处理办法,便是把需求显现的图形在后台线程制作为图片,防止运用圆角、暗影、遮罩等特色。
    

常用优化手法

  • 削减视图数量和层次,可把多个视图预先烘托为一张图片

  • 不要让图片和视图超越GPU可烘托的最大尺度

  • 视图不通明

  • 防止离屏烘托 OpenGL 中,GPU 屏幕烘托有以下两种办法:

    • On-Screen Rendering 意为当时屏幕烘托,指的是 GPU 的烘托操作是在当时用于显现的屏幕缓冲区中进行。

    • Off-Screen Rendering 意为离屏烘托,指的是 GPU 在当时屏幕缓冲区以外新拓荒一个缓冲区进行烘托操作。

    比较于当时屏幕烘托,离屏烘托的价值是很高的,首要体现在两个方面:

    • 创立新缓冲区 要想进行离屏烘托,首先要创立一个新的缓冲区。

    • 上下文切换 离屏烘托的整个进程,需求屡次切换上下文环境:先是从当时屏幕(On-Screen)切换到离屏(Off-Screen);比及离屏烘托完毕今后,将离屏缓冲区的烘托成果显现到屏幕上有需求将上下文环境从离屏切换到当时屏幕。而上下文环境的切换是要支付很大价值的。

    所以在图形生成的进程咱们要尽或许的防止离屏烘托

优化东西

188bet注册中,在GPU优化上,咱们一般运用instruments中的Core Animation东西来进行滑动流通度优化,在Core Animation中咱们可也看到列表滑动进程中的FPS,其间有一些很有用的debug选项,协助咱们找到代码中有功用问题的代码。下面是一些常用的选项:

  • Color Blended Layers

    Color Blended Layers是用来检测个半通明图层的混合区,烘托程度对屏幕中的混合区域进行绿到红的高亮。因为核算混合区的色彩时,导致overdraw,耗费必定的GPU资源,是导致滑动功用的一个要素。所以尽量要尽量防止

    在开发进程中,防止Blended Layers的手法有:

    • 设置opaque特色YES

    • View布景色彩不通明

    • Image不含有通明通道

    • 需求特别留意的是,在iOS8之后,UILabel运用的是CALayer作为底图层,而在iOS8开端,UILabel的底图层变成了_UILabelLayer,制作文本也有所改动。UILabel显现中文时,还需masksToBounds = YES。

  • Color Hits Green and Misses Red Color Hits Green and Misses Red用来检测是否正确运用shouldRasterize,当缓存需求从头生成时,赤色高亮rasterized layers,当设置shouldRasterize=YES,会将layer预先烘托成位图,并缓存。以进步功用。可是假如cache频频重复地生成,表明shouldRasterize或许带来的是负面的功用影响。因而shouldRasterize适用于烘托耗时、图画内容不变的状况,在列表中因为内容要频频改动,因而不引荐运用此特色

  • Color Copied Images

    大多数时,Core Animation只需求提交原始图片的指针到render server,不触及内存copy。可是一些状况下,Core Animation不得不copy一份图片发送到render server。苹果的GPU只解析32bit的色彩格局,假如图片色彩格局不对,CPU会预先格局转化。copy images是非常耗CPU的操作,必定要防止。

  • Color Misaligned Images 被拉伸缩放的图片、无法正确对齐到像素的图片(或许有不是整数的的坐标)。是耗CPU的操作

  • Color Offscreen-Rendered Yellow

    GPU在当时屏幕缓冲区外拓荒新的缓冲区进行烘托, 屏幕外缓冲区和当时屏幕缓冲区上下文切换是非常耗时的操作

    引起Offscreen-Rendered的操作有:

      - 圆角 cornerRadius masksToBounds一同设置
      - 设置shadow
      - 敞开光栅化 shouldRasterize=YES.CALayer 有一个 shouldRasterize 特色,将这个特色设置成 true 后就敞开了光栅化。敞开光栅化后会将图层制作到一个屏幕外的图画,然后这个图画将会被缓存起来并制作到实践图层的 contents 和子图层,关于有许多的子图层或许有杂乱的效果运用,这样做就会比重绘一切事务的一切帧来愈加高效。可是光栅化原始图画需求时间,并且会耗费额定的内存。光栅化也会带来必定的功用损耗,是否要敞开就要依据实践的运用场景了,图层内容频频改动时不主张运用。最好仍是用 Instruments 比对敞开前后的 FPS 来看是否起到了优化效果。
      - 图层蒙板

防止Offscreen-Rendered的办法能够其他办法完结圆角、shadow + shadowPath等。

总结

本文的讲了一些形成卡顿的原因,以及CPU和GPU优化的常用技巧和东西,咱们在优化的时分能够作为参阅。但不要把优化手法限制在这些方面,不同的运用有各自不同的特色,必定要具体问题具体分析。乃至能够跳出技能领域,在交互方面做一些文章,比方在削减列表每次从服务器获取的数据数量、选用用户手动点击触发获取更多数据而不是滑动进程中主动获取、运用交互动画等都能够极大改进用户的滑动体会。

最终仍是要着重一下我上一篇文章讲的优化时分需求留意的几大准则,这样才干在优化进程中有更好的大局观,尽量少走弯路,期望咱们能够在优化进程中时间紧记。

共享到:
我来说两句
facelist
您需求登录后才干够谈论 登录 | 当即注册
一切谈论(0)
封闭

每日头条

经过邮件订阅最新 Code4App 信息
上一条 /4 下一条
联络咱们
封闭
协作电话:
13802416937
Email:
[email protected]
商务商场协作/投稿
问题反应及协助
联络咱们

广告投进| 广东互联网违法和不良信息告发中心|我国互联网告发中心|Github|请求友链|手机版|Code4App ( 粤ICP备15117877号-1 )

回来顶部