The reasons for the lag:

The CPU, GPU and display in the system work together in this way. The CPU calculates the display content and submits it to THE GPU. After the GPU finishes rendering, the rendering result is put into the frame buffer. Then the video controller will read the data of the frame buffer line by line according to the VSync signal and transmit it to the display through possible digital-to-analog conversion.

Upon the arrival of VSync signal, 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, picture decoding, text drawing, etc. Then THE CPU will submit the calculated content to the GPU, which will transform, synthesize and render. The GPU then submits the rendering result to the frame buffer and waits for the next VSync signal to be displayed on the screen. Due to the VSync mechanism, if the CPU or GPU does not complete the content submission within a VSync period, the frame will be discarded and displayed at the next opportunity, while the display will keep the previous content unchanged. That’s why the interface gets stuck.

Causes and solutions of CPU resource consumption

Object creation

Object creation allocates memory, adjusts properties, and even reads files. Try to use lightweight objects instead of heavy objects.

Things like CALayer are lighter than UIView, so you can use CALayer instead of UIView if the view doesn’t involve touches, or you can put the creation of UIView into a background thread if the view doesn’t involve UI.

Creating view objects in storyboard is much more expensive than creating them directly in code, and storyboard is not a good technology choice for performance-sensitive interfaces.

Delay object creation as long as possible and spread it out among multiple tasks.

If objects can be reused and the cost of reuse is less than releasing and creating new objects, then such objects should be reused in a cache pool as much as possible.

Object to adjust

Object tuning is a common CPU drain, UIView properties such as Bounds, frame, center, etc., when adjusting UIView properties, because CALayer has no properties, when calling the properties, a temporary method is generated, and the value is stored in a dictionary of CALayer at the end of the call, so when adjusting UIView properties, There’s going to be a bunch of notifications and proxies between UIView and CALayer.

When the view hierarchy is adjusted, there are many method calls and notifications between UIView CALayer, so when optimizing performance, you should try to avoid adjusting the view hierarchy to add and remove views.

Object is destroyed

The destruction of objects consumes relatively few resources, and is usually noticeable when a container class holds a large number of objects, so you should put the destruction process into background threads.

The best solution is to use a BLOCK to capture an object and then send a message to the object in a background thread within the BLOCK to destroy the object in the background

Layout calculation

Layout computing is also a common CPU drain. When the layout inside the page is very complex, it is best to calculate the layout in the background ahead of time

AutoLayout

AutoLayout is a layout method recommended by Apple, which can significantly improve the layout efficiency. However, the resource consumption of complex pages increases exponentially. Therefore, AutoLayout should not be used for layout of complex pages

The text calculated

If an interface contains a large amount of text (such as weibo and wechat moments, etc.), text width and height calculation will occupy a large portion of resources and is inevitable. If you have no special requirements for text display, you can refer to the internal implementation of UILabel: With [NSAttributedString boundingRectWithSize: options: context:] to calculate the text width is high, Use – [NSAttributedString drawWithRect: options: context:] to draw text. Although these two methods perform well, they still need to be put into background threads to avoid blocking the main thread.

If you draw text in CoreText, you can create a CoreText typeset object and do the calculation yourself, and the CoreText object can be saved for later drawing.

Text rendering

All text content controls that can be seen on the screen, including UIWebView, are at the bottom of the page formatted and drawn as bitmaps through CoreText. Common text controls (UILabel, UITextView, etc.), its typesetting and drawing are carried out in the main thread, when the display of a large number of text, the CPU pressure will be very large. There is only one solution, and that is a custom text control that asynchronously draws text using TextKit or the low-level CoreText. Once the CoreText object is created, it can directly obtain the width and height of the text, avoiding multiple calculations (once when the UILabel size is adjusted, and again when the UILabel is drawn). CoreText objects take up less memory and can be cached for later multiple renders.

Image decoding

When you create an image using UIImage or CGImageScoure, the image does not immediately decode. The image is set to UIImageView or calayer.contents, and the data in the CGImage is decoded before the CALayer is submitted to the GPU. This step happens on the main thread. If you want to circumvent this mechanism, a common practice is to put the image into CGBitmapContext in the background line and then create the image directly from the Bitmap. At present, the common network photo library has this function

Image rendering

Drawing an image usually refers to the process of drawing an image onto a canvas using methods that begin with CG, and then creating and displaying the image from the canvas. The most common place to do this is inside [UIView drawRect:]. Since CoreGraphic methods are usually thread-safe, drawing images can easily be put into background threads.

Causes and solutions of CPU resource consumption

What the GPU can do is relatively simple: take a submitted Texture and vertex description, apply a transform, mix and render, and then print it to the screen.

Texture rendering

All bitmaps including images and text will eventually be committed from memory to video memory and bound to the GPU Texture. Both the process of submitting to video memory and the process of GPU adjusting and rendering Texture consume a lot of GPU resources.

CPU usage is low when displaying a large number of images in a short period of time. GPU usage is very high and the interface still drops frames. The only way to avoid this situation is to minimize the display of a large number of pictures in a period of time, and to display as many pictures as possible.

Mixing of views

When multiple views (or Calayers) are displayed on top of each other, the GPU blends them together first. If the view structure is too complex, the mixing process will consume a lot of GPU resources. In order to reduce the GPU consumption in this situation, the number and layers of views should be reduced as much as possible, and opaque attributes should be displayed in the opaque view to avoid useless Alpha channel composition.

Graph generation

CALayer’s border/ rounded corner/shadow/mask usually triggers off-screen rendering, which usually happens on a GPU. When there are a lot of rounded calayers in a list view and a quick swipe, you can observe that the GPU is full and the CPU is consuming very little. The interface still slides normally, but the average number of frames drops to a very low level.

For some situations where rounded corners are required, you can also overlay the original view with an already drawn rounded corner image to simulate the same visual effect. The best solution is to draw the graphics you want to display as images in the background, avoiding rounded corners/shadows/masks.


image.png

Blog.ibireme.com/2015/11/12/…