Summary of iOS performance optimization

Click " iOS Development " above and select "Public Account"

Critical moment, the first time delivery!

640?wxfrom=5&wx_lazy=1

640?wx_fmt=gif&wxfrom=5&wx_lazy=1


Cause of Caton


640?wx_fmt=other&wxfrom=5&wx_lazy=1


After the VSync signal arrives, the system graphics service will notify the App through CADisplayLink and other mechanisms, and the main thread of the App will start to calculate the display content in the CPU, such as view creation, layout calculation, image decoding, text drawing, etc. Then the CPU will submit the calculated content to the GPU, and the GPU will transform, synthesize, and render it. The GPU will then submit the rendering results to the frame buffer, waiting for the next VSync signal to be displayed on the screen. Due to the vertical synchronization mechanism, if the CPU or GPU does not complete the content submission within a VSync time, the frame will be discarded and displayed again after the next opportunity, and the display screen will retain the previous content unchanged. This is why the interface is stuck.


During development, excessive pressure on either CPU or GPU will result in dropped frames. Therefore, during development, it is also necessary to evaluate and optimize the pressure on CPU and GPU respectively.


CPU & GPU in iOS devices


CPU


Loading resources, object creation, object adjustment, object destruction, layout calculation, Autolayout, text calculation, text rendering, image decoding, and image drawing (Core Graphics) are all performed on the CPU.


GPU


GPU is a processing unit specially tailored for high-concurrency computing of graphics. It uses less electricity to complete work than CPU and the floating-point computing power of GPU is much higher than that of CPU.


The rendering performance of the GPU is much more efficient than that of the CPU, and the load and consumption of the system are also lower. Therefore, in the development, we should try to let the CPU be responsible for the UI transfer of the main thread, and hand over the work related to graphics display to the GPU for processing. , when it comes to some work such as rasterization, the CPU will also participate, which will be described in detail later.


Compared with the CPU, the GPU can do a single thing: receive the submitted texture (Texture) and vertex description (triangle), apply transformation (transform), blend (compositing) and render, and then output to the screen. Usually what you can see is mainly two types of textures (pictures) and shapes (vector graphics of triangular simulation).


Collaboration of CPU and GPU


640?wx_fmt=other


As can be seen from the above figure, to display the view on the screen, the CPU and GPU need to cooperate together. The CPU calculates the displayed content and submits it to the GPU. After the GPU rendering is completed, the result is placed in the frame buffer area. Then the video controller will follow the VSync signal one by one. The line reads the data from the frame buffer and passes it to the monitor for display after possible digital-to-analog conversion.


buffer mechanism


640?wx_fmt=other


iOS uses a double buffering mechanism. That is, the GPU will pre-render a frame into a buffer (previous frame buffer), and let the video controller read it. After the next frame is rendered, the GPU will directly point the pointer of the video controller to the second buffer ( post frame buffer). When your video controller has finished reading a frame and is ready to read the next frame, the GPU will wait for the VSync signal of the display to be sent, the front frame buffer and the rear frame buffer will switch instantly, and the rear frame buffer will become the new previous frame. buffer, and the old pre-frame buffer becomes the new post-frame buffer.


Optimization


The reasons and solutions for CPU resource consumption and  GPU resource consumption reasons and solutions are introduced in detail  in YY's  iOS Tips for Keeping the Interface Smooth . This includes most of the scenarios in development, which can help us quickly locate the cause of the freeze. , quickly resolve the stuck.


Here are some common optimization scenarios!


TableViewCell reuse


In the cellForRowAtIndexPath: callback, only an instance is created, and the cell is quickly returned without binding data. Bind data (assignment) when willDisplayCell: forRowAtIndexPath:.


Highly cached


When the tableView slides, heightForRowAtIndexPath: will be called continuously. When the cell height needs to be adaptive, the height needs to be calculated every time the callback is called, which will cause the UI to freeze. To avoid repeating meaningless calculations, the height is cached.


How to cache?
  • Dictionary, NSCache.

  • UITableView-FDTemplateLayoutCell


View level optimization


Don't dynamically create views
  • Under the premise of controllable memory, cache the subview.

  • Make good use of hidden.


reduce view hierarchy
  • Reduce the number of subviews and use layers to draw elements.

  • 少用clearColor,maskToBounds,阴影效果等。


减少多余的绘制操作


图片


  • 不要用JPEG的图片,应当使用PNG图片。

  • 子线程预解码(Decode),主线程直接渲染。因为当image没有Decode,直接赋值给imageView会进行一个Decode操作。

  • 优化图片大小,尽量不要动态缩放(contentMode)。

  • 尽可能将多张图片合成为一张进行显示。


减少透明 view


使用透明view会引起blending,在iOS的图形处理中,blending主要指的是混合像素颜色的计算。最直观的例子就是,我们把两个图层叠加在一起,如果第一个图层的透明的,则最终像素的颜色计算需要将第二个图层也考虑进来。这一过程即为Blending。

会导致blending的原因:

  • UIView的alpha<1。

  • UIImageView的image含有alpha channel(即使UIImageView的alpha是1,但只要image含有透明通道,则仍会导致blending)。


为什么blending会导致性能的损失?


原因是很直观的,如果一个图层是不透明的,则系统直接显示该图层的颜色即可。而如果图层是透明的,则会引起更多的计算,因为需要把另一个的图层也包括进来,进行混合后的颜色计算。


  • opaque设置为YES,减少性能消耗,因为GPU将不会做任何合成,而是简单从这个层拷贝。


减少离屏渲染


离屏渲染指的是在图像在绘制到当前屏幕前,需要先进行一次渲染,之后才绘制到当前屏幕。


OpenGL中,GPU屏幕渲染有以下两种方式:


  • On-Screen Rendering即当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行。

  • Off-Screen Rendering即离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。


为什么离屏渲染会发生卡顿?主要包括两方面内容:


  • 创建新的缓冲区。

  • 上下文切换,离屏渲染的整个过程,需要多次切换上下文环境(CPU渲染和GPU切换),先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上又需要将上下文环境从离屏切换到当前屏幕。而上下文环境的切换是要付出很大代价的。


设置了以下属性时,都会触发离屏渲染:


  • layer.shouldRasterize,光栅化

  • layer.mask,遮罩

  • layer.allowsGroupOpacity为YES,layer.opacity的值小于1.0

  • layer.cornerRadius,并且设置layer.masksToBounds为YES。可以使用剪切过的图片,或者使用layer画来解决。

  • layer.shadows,(表示相关的shadow开头的属性),使用shadowPath代替。

  • 两种不同方式来绘制阴影: 不使用shadowPath


640?wx_fmt=other


使用shadowPath


640?wx_fmt=other


性能差别,如下图:


640?wx_fmt=other


离屏渲染的优化建议


  • 使用ShadowPath指定layer阴影效果路径。

  • 使用异步进行layer渲染(Facebook开源的异步绘制框架AsyncDisplayKit)。

  • 设置layer的opaque值为YES,减少复杂图层合成。

  • 尽量使用不包含透明(alpha)通道的图片资源。

  • 尽量设置layer的大小值为整形值。

  • 直接让美工把图片切成圆角进行显示,这是效率最高的一种方案。

  • 很多情况下用户上传图片进行显示,可以在客户端处理圆角。

  • 使用代码手动生成圆角image设置到要显示的View上,利用UIBezierPath(Core Graphics框架)画出来圆角图片。


合理使用光栅化 shouldRasterize


光栅化是把GPU的操作转到CPU上,生成位图缓存,直接读取复用。


优点:
  • CALayer会被光栅化为bitmap,shadows、cornerRadius等效果会被缓存。


缺点:
  • 更新已经光栅化的layer,会造成离屏渲染。

  • bitmap超过100ms没有使用就会移除。

  • 受系统限制,缓存的大小为 2.5X Screen Size。


shouldRasterize适合静态页面显示,动态页面会增加开销。如果设置了shouldRasterize为YES,那也要记住设置rasterizationScale为contentsScale。


异步渲染


在子线程绘制,主线程渲染。例如 VVeboTableViewDemo


640?wx_fmt=other


理性使用-drawRect:


大家或许感到奇怪,有不少开发者在发有关性能优化的博客当中指出使用-drawRect:来优化性能。但是我这里不太建议大家未经思考的使用-drawRect:方法。原因如下:


当你使用UIImageView在加载一个视图的时候,这个视图虽然依然有CALayer,但是却没有申请到一个后备的存储,取而代之的是使用一个使用屏幕外渲染,将CGImageRef作为内容,并用渲染服务将图片数据绘制到帧的缓冲区,就是显示到屏幕上,当我们滚动视图的时候,这个视图将会重新加载,浪费性能。所以对于使用-drawRect:方法,更倾向于使用CALayer来绘制图层。因为使用CALayer的-drawInContext:,Core Animation将会为这个图层申请一个后备存储,用来保存那些方法绘制进来的位图。那些方法内的代码将会运行在CPU上,结果将会被上传到GPU。这样做的性能更为好些。


静态界面建议使用-drawRect:的方式,动态页面不建议。


按需加载

  • 局部刷新,刷新一个cell就能解决的,坚决不刷新整个section或者整个tableView,刷新最小单元元素。

  • 利用runloop提高滑动流畅性,在滑动停止的时候再加载内容,像那种一闪而过的(快速滑动),就没有必要加载,可以使用默认的占位符填充内容。


关于性能测试


After image performance problems, sliding, and animations are not smooth enough, the first thing we need to do is to locate the problem. And this process is not only based on experience and exhaustive exploration, we should use scientific methods with context and order to explore

First, we have to have a pattern for locating the problem. We can locate the problem step by step in this order.


  1. Positioning the frame rate, in order to give users a smooth feeling, we need to keep the frame rate around 60 frames. When we encounter problems, we first check if the frame rate remains at 60 fps.

  2. Locate the bottleneck, whether it is the CPU or the GPU. We hope that the occupancy rate is as low as possible, one is for fluency, and the other is to save power.

  3. Check if unnecessary CPU rendering is done, for example, we override drawRect: in some places, which we don't need and shouldn't. We want the GPU to do more of the work.

  4. Check for excessive off-screen rendering, which consumes GPU resources, as already analyzed. Offscreen rendering will cause the GPU to constantly switch context between onScreen and offscreen. We would like to have less off-screen rendering.

  5. Check if we have too much Blending, GPU rendering an opaque layer is more resource efficient.

  6. Check whether the format of the picture is a common format and whether the size is normal. If an image format is not supported by the GPU, it can only be rendered by the CPU. Generally, we should use the PNG format in iOS development. Some of the materials we have read before also pointed out that Apple has specially optimized the rendering and compression algorithms for the PNG format.

  7. Check whether there are Views or effects that consume a lot of resources, we need to use them reasonably and sparingly.

  8. Finally, we need to check for any inaccuracies in our View hierarchy. For example, sometimes we constantly add or remove Views, sometimes inadvertently lead to bugs.


test tools:
  • Core Animation, a tool for testing graphics performance issues in Instruments.

  • view debugging, which comes with Xcode, the view hierarchy.

  • reveal, the view level.




640?

  • Author: LaiYoung_
  • Link: https://juejin.im/post/5ace078cf265da23994ee493

  • iOS development, finishing and publishing, please contact the author for authorization to reprint

640?wx_fmt=gif640?[Click to become a Java God]

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324643501&siteId=291194637