SoFunction
Updated on 2025-04-13

Detailed sorting out the performance optimization of UITableView in iOS

1. Introduction

In iOS development, UITableView may be one of the UI controls we deal with the most, and its importance is self-evident. The same is true for Android. ListView and UITableView in Android are a control with the same functions, but the UITableView in iOS is more powerful. I won’t mention the reason. If you have learned Android, you will know that UITableView in iOS is very simple to use. This is also one of the reasons why Brother Feng likes iOS better than Android. What we are studying today is the optimization of UITableView.

Before you start, how many UITableView can you name? cell reuse (reuse of ListView in Android is often called. In fact, reuse and reuse are the same. Because Brother Feng had done Android before, sometimes I often say "reuse". If you say "reuse" later, it's enough to say "reuse" means "reuse")! What about reuse except cell?

2. Performance optimization of UITableView

1. Cell reuse

Reuse is simple, and this is perhaps the most familiar optimization content for all iOS developers, as follows:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 static NSString *Identifier = @"cell";
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
 if (!cell) {
 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
 }
 
 return cell;
}

But is it perfect to reuse like this?

We often pay attention to the cellForRowAtIndexPath: to bind data for each cell. In fact, the cell has not been displayed when calling cellForRowAtIndexPath:. In order to improve efficiency, we should place the data binding operation after the cell is displayed before executing it. You can bind data in the tableView: willDisplayCell: forRowAtIndexPath: (hereinafter referred to as willDisplayCell) method.

Note that willDisplayCell will be called before the cell is displayed before the tableview is displayed. At this time, the cell instance has been generated, so the cell structure cannot be changed. It can only change some properties of the UI on the cell (such as the content of the label, etc.).

2. Calculation of cell height

Here we are divided into two types of cells, one is a cell with a fixed height, and the other is a cell with a dynamic height.

(1) The cell with a fixed height should be used as follows:

 = 88;

This method specifies that all cell heights are 88 tableviews, and the default value of rowHeight is 44, so an empty TableView will be displayed like this. For the fixed height cell, the above method is used to directly define the height, and there is no need to implement tableView:heightForRowAtIndexPath: to save unnecessary calculations and overhead.

(2) Dynamic height cell

We need to implement its proxy to give the height:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
 // return xxx
}

After this proxy method is implemented, the above rowHeight setting will become invalid. In this method, we need to improve the cell's high computing efficiency to save time.

Since iOS8, the concept of self-sizing cell has been developed. The cell can calculate its height by itself. Using self-sizing cell requires the following three conditions:

(1) Use Autolayout to perform UI layout constraints (the required four edges are all constrained to internal elements).

(2) Specify the default value of the estimatedRowHeight property of TableView.

(3) Specify the rowHeight property of TableView to be UITableViewAutomaticDimension.

- (void)viewDidload {
  = 44.0;
  = UITableViewAutomaticDimension;
}

In addition to improving the computing efficiency of cell height, we need to cache the calculated height. For the calculated height, there is no need to calculate the second time.

3. Rendering

In order to ensure the smoothness of the TableView, the cell must be rendered quickly when sliding quickly. So the cell rendering speed must be fast. How to improve the rendering speed of the cell?

(1) When there is an image, pre-render the image, draw it in the bitmap context first, export it into a UIImage object, and then draw it to the screen, which will greatly improve the rendering speed. For specific content, you can find the relevant information about "Using pre-rendering to accelerate the display of iOS images".

(2) One of the best rendering operations is blending, so we should not use transparent backgrounds, set the cell's opaque value to Yes, do not use clearColor in the background color, try not to use shadow gradients, etc.

(3) Since the mixing operation is performed using the GPU, we can render it with the CPU, so the mixing operation will no longer be performed. You can customize the drawing in the drawRect method of UIView.

4. Reduce the number of views

When we add system controls on the cell, the system will actually call the underlying interface to draw. When adding a large number of controls, it will consume a lot of resources and will also affect the rendering performance. It consumes performance when using the default UITableViewCell and adding controls on its ContentView. So the best way to do so at present is to inherit UITableViewCell and override the drawRect method.

5. Reduce unnecessary drawing operations

When implementing the drawRect method, its parameter rect is the area we need to draw. We do not need to draw areas outside the rect range, otherwise it will consume considerable resources.

6. Do not add subView dynamically to cell

When initializing the cell, add all the displays to the cell, and then set the hide attributes to display and hide as needed.

7. Asynchronous UI, do not block the main thread

We often see a phenomenon that the entire page cannot be stuck during loading, and it is useless to click it, as if it has crashed. The reason is that the main thread is blocked. Therefore, for network data requests or pictures loading, we can enable multi-threading, put time-consuming operations into child threads, and asynchronous operations. This is something that every iOS developer knows, so there is no need to talk about.

8. Load the corresponding content as needed when sliding

If the target row differs from the current row more than the specified number of rows, only 3 rows are specified before and after the target scroll range.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
 NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];
 NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject];
 NSInteger skipCount = 8;
 if (labs()>skipCount) {
  NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, , )];
  NSMutableArray *arr = [NSMutableArray arrayWithArray:temp];
  if (<0) {
   NSIndexPath *indexPath = [temp lastObject];
   if (+33) {
    [arr addObject:[NSIndexPath indexPathForRow:-3 inSection:0]];
    [arr addObject:[NSIndexPath indexPathForRow:-2 inSection:0]];
    [arr addObject:[NSIndexPath indexPathForRow:-1 inSection:0]];
   }
  }
  [needLoadArr addObjectsFromArray:arr];
 }
}

Remember to add judgment in the tableView:cellForRowAtIndexPath: method:

if (>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) {
 [cell clear];
 return;
}

When sliding very quickly, only the cells within the target range are loaded, so as to load as needed (with SDWebImage), greatly improving the smoothness.

Summarize

The above is the entire content of this article. I hope the content of this article will be of some help to your study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.