This is the seventh day of my participation in the August More text Challenge. For details, see:August is more challenging

Realize my problem

When reading news every day, I will feel that the news app is still very good. When the TableView Cell scrolls, it will not load and display the picture content. After a slide, the news pictures on the Cell will start to load and display one by one. So the whole process of sliding is very smooth. The experience is also quite nice.

What I did in the beginning

Development of the use of TableView is very frequent value, when the TableViewCell needs to load pictures, is a headache. Because the user is sliding the TableView, the TableView needs to be fetching pictures from the network at the same time. The previous operation was handled in cellForRowAtIndexPath, which caused the user to swipe the TableView very hard (especially if the slide was very fast), and the CPU usage of the phone was very high. This is clearly a very bad experience for the user.

Bad picture display code

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    ImageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    cell.index = indexPath;
    
    NSMutableDictionary *info = [self.dataSource objectAtIndex:cell.index.row];

    NSString *url = [info objectForKey: @"img" ];
    NSData *iData = [NSData dataWithContentsOfURL:[NSURL URLWithString: url ]];
    cell.img.image = [UIImage imageWithData:iData];
    cell.typeL.text = [NSString stringWithFormat:@"%ld-%ld", cell.index.section, cell.index.row];

    return cell;
}
Copy the code

Poor mobile CPU surge rates

Poor user swiping experience

It’s not just a user experience, it’s also an unacceptable experience for developers.

I often touch and use a lot of apps, and I found that their multi-processing method is that when users swipe the list, they will no longer load the pictures, and after the user slides, they will start to load the pictures one by one. This is a great optimization that takes the load off the CPU and basically doesn’t cause the user to feel stuck scrolling. This is what I described at the beginning of my experience with the news app.

With that in mind, let’s set out to make the worst of the experience.

Summarize ideas to open the road of optimization

So, with that optimization in mind, I started to optimize this TableView.

  • First, we only load the images on the cell that the current user can see.
  • Second, we only load one image at a time.

To do both, the image loading and display cannot be done in cellForRowAtIndexPath. We need to define and implement a loading and display method for the image, so that when the time is right, the refresh content display is called.

LoadSeeImage Load image optimization

#pragma mark load Images - (void)loadSeeImage {NSInteger loadC = 0; NSArray *cells = [self.imagetableView visibleCells]; // Dispatch group dispatch_group_t group = dispatch_group_create(); for (int i = 0; i < cells.count; i++) { ImageTableViewCell *cell = [cells objectAtIndex:i]; NSMutableDictionary *info = [self.dataSource objectAtIndex:cell.index.row]; NSString *url = [info objectForKey: @"img" ]; NSString *data = [info objectForKey:@"data"]; If ([data isKindOfClass:[NSData class]]) {}else {// Add dispatch_group_async(group, self.loadqueue, ^{ NSData *iData = [NSData dataWithContentsOfURL:[NSURL URLWithString: url ]]; NSLog(@" load image %ld-%ld ", cell.index.section, cell.index.row); If (iData) {// cache [info setValue:@"1" forKey:@"isload"]; [info setValue:iData forKey:@"data"]; } NSString *isload = [info objectForKey:@"isload"]; if ([isload isEqualToString:@"0"]) { dispatch_async(dispatch_get_main_queue(), ^{ cell.img.image = [UIImage imageNamed:@""]; }); }else { if (iData) { dispatch_async(dispatch_get_main_queue(), ^{cell.img.image = [UIImage imageWithData:iData]; }); }}}); if (i == cells.count - 1) { dispatch_group_notify(group, dispatch_get_main_queue(), ^{// NSLog(@"load finished"); }); } loadC += 1; }} NSLog(@" %ld images loaded ", loadC); }Copy the code

The second is the handling of the timing of the loadSeeImage call. We want to make sure that the user loads after sliding the list, which is in the following two places:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView   {  
    
    [self loadSeeImage];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    
    if (scrollView.isDragging || scrollView.isDecelerating || scrollView.isTracking) {
        return;
    }
    [self loadSeeImage];
}
Copy the code

Of course, the first time we enter the page, after the list of data loaded, we also want to load the image oh. Ok, let’s look at the optimized results:

CPU usage is down by more than half from its previous peak, and there is no noticeable lag in the app sliding. Perfect.