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.