Today the product manager told me: hey, who, this interface is very card ah!! Look what’s going on… So I took out the Core Animation in Instrument and looked at the FPS, and found that the FPS was very low when sliding!

Causes of caton

First of all, look up the information to see why there is the cause of lag.

Mass geometry

All bitmaps, including images, text and rasterized content, are eventually 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. When a large number of images are displayed in a short period of time (such as when the TableView has a large number of images and slides quickly), the CPU usage is very low and the GPU usage is very high, and the interface will still drop frames. The only way to avoid this situation is to minimize the display of a large number of pictures in a short period of time, and to display as many pictures as possible. In addition, when the image is too large to exceed the maximum texture size of the GPU, the image needs to be preprocessed by the CPU, which will bring additional resource consumption to the CPU and GPU.

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 can also consume a lot of GPU resources. To reduce GPU consumption in this situation, applications should minimize the number and level of views and reduce unnecessary transparent views.

Off-screen rendering

Off-screen rendering is when a layer is rendered in a buffer outside the current screen buffer before being displayed. Off-screen rendering requires multiple context switches: first from the current Screen to off-screen; When the off-screen rendering is finished, the rendering results of the off-screen buffer are displayed on the screen, and the context environment needs to be switched from off-screen to the current screen, which is a costly action. Can cause offscreen rendering reasons: shadow (UIView. Layer. ShadowOffset shadowRadius /…). Rounded corners (when UIView. Layer. The cornerRadius and UIView layer. MaskToBounds when used together) layer mask open rasterizer (shouldRasterize = true)

The rounded optimization

Therefore, we found the reason. Since our project was based on the map, we directly added pages on the map. Before, the map had many rounded corners, and the rounded corners on the cell would cause GPU performance loss. Which brings us back to the age-old question of optimizing rounded corners. The previous article said that to optimize:

+ (void)cutRadiousWithView:(UIView *)view radious:(CGFloat)radious { UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radious, radious)]; CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init]; // Set the size masklayer.frame = view.bounds; // MaskLayer. path = maskpath. CGPath; view.layer.mask = maskLayer; }Copy the code

However, the discovery does not help, in fact, the mask will still render off-screen. And the FPS seems to be lower in real time. (Black question mark face)

Image fillet optimization

So I continued to look up the information and found that the rounded corners of the picture could be redrawn to get a new picture. The method is as follows:

+ (UIImage *)cutCircleImageWithImage:(UIImage *)image size:(CGSize)size radious:(CGFloat)radious {
    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);

    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    CGContextAddPath(UIGraphicsGetCurrentContext(),
                 [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radious].CGPath);
    CGContextClip(UIGraphicsGetCurrentContext());

    [image drawInRect:rect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
Copy the code

You can use this method to get new images, you can do this for rounded corners of images, but what about views?

View fillet optimization

“View” can cover it with an ImageView and set the image of the ImageView as follows:

+ (void)cutCicleViewWithView:(UIView *)view radious:(CGFloat)radius {
    CGSize size = view.frame.size;
    CGRect rect = CGRectMake(0, 0, size.width, size.height);
    UIColor *bkColor = view.backgroundColor;

    UIImage *image = [[UIImage alloc] init];
    UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, bkColor.CGColor);
    CGContextAddPath(context,
                 [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius].CGPath);
    CGContextDrawPath(context, kCGPathFill);
    [image drawInRect:rect];
    UIImage *output = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:rect];
    imageView.image = output;
    [view insertSubview:imageView atIndex:0];
    view.backgroundColor = [UIColor clearColor];
}
Copy the code

conclusion

I believe those of you who have studied algorithms know that the faster the algorithm, the higher the spatial complexity. When you optimize for one performance, you inevitably lose other performance, so called algorithm optimization is to achieve the best implementation effect. So the result of optimizing the GPU in this way is CPU loss. Premature optimization is evil, but by the time the problem is solved, something is necessary!

References:

http://www.reviewcode.cn/article.html?reviewId=7 http://ios.jobbole.com/92237/