IOS list performance optimization – picture decoding performance optimization

Time:2022-1-2

preface

Why do I need to decode pictures?

In fact, both JPEG and PNG pictures are compressed bitmap graphics format. However, PNG pictures are lossless compression and support alpha channel, while JPEG pictures are lossy compression, and the compression ratio of 0-100% can be specified. Therefore, before rendering the pictures in the disk to the screen, the original pixel data of the pictures must be obtained before subsequent drawing operations can be performed. This is why it is necessary to decompress the pictures. See detailsTalk about image decompression in IOSImage format problem and performance optimization in IOSIOS development: image format and performance optimization

1. How many cards are there in picture decoding?

The test method is relatively simple. Pictures can be displayed in a tableview. Pictures are 10 pictures that have been placed locally, and each picture is greater than 1MB

The code is as follows:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    BannerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BannerTableViewCell" forIndexPath:indexPath];
    
    //Get picture
    NSInteger index = 0;
    index = indexPath.row%10;
    NSString *imageName = [NSString stringWithFormat:@"backImage%ld",(long)index];
    //UIImage *image = [UIImage imageNamed:imageName];
    
    NSString *path = [[NSBundle mainBundle] pathForResource:imageName ofType:@"jpg"];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    
    cell.contentImageView.image = image; 
    return cell;
}

Careful students may have noticed that I wrote two ways to load pictures in the code.
One is: [uiimage imagenamed: imagename]
One is: [uiimage imagewithcontentsoffile: path]
Later, I will explain why we need to compare the two loading methods. Let’s start with the loading results.

1> Use [uiimage imagewithcontentsoffile: path]

IOS list performance optimization - picture decoding performance optimization

image.png

2> Use [uiimage imagenamed: imagename]

IOS list performance optimization - picture decoding performance optimization

image.png

Both methods actually slide for one minute. It can be clearly seen that the number of frames in both loading methods is very low at the beginning, but the number of frames using imagenamed: will soon recover to 60, but using imagewithcontentsoffile: will always get stuck. That’s because using imagenamed: will cache pictures, but imagewithcontentsoffile: will not, Moreover, using imagewithcontentsoffile: there is an obvious jam and frame loss. From the curve, we can clearly see the difference between the two methods.

Let’s explain the two loading methods we use. Imagewithcontentsoffile: actually simulates the process of downloading pictures from the network to the local and then loading display pictures from the local. Imagenamed: simulates the process of downloading pictures from assets When loading pictures in xcassets, you can clearly see that apple is right from assets Xcassets has been optimized for loading pictures.

2. How to optimize the picture decoding part

The scheme is simple: the decoding process can be directly placed in the sub thread. After decoding, the image can be assigned to ImageView in the main thread Image and cache it. The next time you find the same image again, you can read it directly in the cache.
Does this process sound familiar? Yes, this process has been implemented by many third-party libraries, the most famous of which is sdwebimage. The decoding method of sdwebimage is decodedimagewithimage, which uses cgcontextdrawimage. Interested partners can take time to have a look. I won’t repeat it here, but directly optimize the code:

[self queryImageCache:imageName block:^(UIImage *image) {
        cell.contentImageView.image = image;
    }];

- (void)queryImageCache:(NSString *)filename block:(void(^)(UIImage *image))block
{
    //Fetch from the memory. If you don't get it, read the file directly and cache it
    UIImage *image = [self.memCache objectForKey:filename];
    if(image)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            if(block)
                block(image);
        });
    }
    else
    {
        //Put the decompression operation into the child thread
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:@"jpg"];
            UIImage *image = [UIImage imageWithContentsOfFile:path];
            
            image = [UIImage decodedImageWithImage:image];
            [self.memCache setObject:image forKey:filename];
            
            //Synchronous main thread
            dispatch_async(dispatch_get_main_queue(), ^{
                if(block)
                    block(image);
            });
       });
    }
}

After experimenting with the above methods, repeat the previous method to check the FPS and CPU usage

IOS list performance optimization - picture decoding performance optimization

image.png
name FPS (average) CPU (average) Experimental time
imageWithContentsOfFile: 47.8 28% 1min
imageNamed: 58.8 10% 1min3
After optimization 59.9 7% 1min9

I hope that the implementation of webimage can be improved after the CPU is optimized, but I hope that it can be put in the list, no matter how many frames are used.

Refer to the following technical Blogs:
https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/
https://www.jianshu.com/p/f9ef5dba9ba3?_dt_push=1
http://www.cocoachina.com/cms/wap.php?action=article&id=24599

Recommended Today

Vue2 technology finishing 3 – Advanced chapter – update completed

3. Advanced chapter preface Links to basic chapters:https://www.cnblogs.com/xiegongzi/p/15782921.html Link to component development:https://www.cnblogs.com/xiegongzi/p/15823605.html 3.1. Custom events of components 3.1.1. Binding custom events There are two implementation methods here: one is to use v-on with vuecomponent$ Emit implementation [PS: this method is a little similar to passing from child to parent]; The other is to use ref […]