The purpose of this blog is to summarize the performance optimization direction of UITableView, some optimization methods are used in my development, some are not used, which also have reference, view a lot of big god summary, this blog, just for your reference!


1. The Cell reuse

1.1> Data source method optimization

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;Copy the code

The page is repeatedly drawn on visible pages, and new cells are created each time the display is refreshed, which is very costly in performance. Solution: First create a static variable reuseID, then fetch the corresponding identifier Cell from the cache pool and update the data. If not, alloc the new Cell. Use an identifier to identify the Cell. Each Cell will register an identifier (reuse identifier) and put it into the cache pool. When it needs to be called, it will directly find the corresponding ID from the cache pool. When it is not needed, it will put it into the cache pool and wait for the call. (Cells removed from the screen are put into the cache pool, not released) So optimize the data source method as follows:

Static NSString *reuseID = "reuseCellID";Copy the code
/ / buffer pool is created cell UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: reuseID];Copy the code

1.2> Implementation of cache pools

When a Cell alloc, the UITableView creates a chunk of memory in the heap for the Cell cache. The reuse of cells identifies different types of cells through identifiers. Therefore, it can be inferred that the outer layer of the cache pool may be a variable dictionary, and the internal cells can be retrieved through keys, while the cache pool stores cells of different heights and types (including images and labels). It can be inferred that the dictionary inside the cache pool might contain a mutable array of different types of cells, and only the different types of cells that have been moved off the screen will be held in the cache pool.

1.3> Differences between two methods of obtaining reusable cells by cache pool

-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier; Copy the code

This method looks for reusable cells, and if the prototype Cell is registered, it can be found, otherwise it returns nil; If (cell == nil) is not recommended

-(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);Copy the code

Before using this method, reusable cells must be registered through xiB (storyboard) or Class (pure code), and this method must return a Cell

Registration of the Cell

- (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(5_0);
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);Copy the code

Benefits: If the buffer Cell does not exist, the prototype Cell will be used to instantiate a new Cell, no need to judge, and the code structure is clearer.


2. Define a (minimal) type of Cell and use hidden to hide subviews

2.1> One type of Cell

Analyze the Cell structure and extract the same content into a style Cell as much as possible. The Cell reuse mechanism mentioned above can ensure how much content UITbaleView needs to display. The actual created Cell may only be a little more than the Cell displayed on the screen. Although the ‘size’ of the Cell may be larger, it is totally acceptable because the number of cells is not very large. Benefits:

  • Reduce the amount of code, reduce the number of Nib files, unified Nib file definition Cell, easy to modify and maintain

  • Based on Cell reuse, the number of cells required to actually populate the screen at run time is roughly fixed, set to N. So if there is only one type of Cell, then there are only N instances of cells; However, if there are M types of cells, the runtime is likely to be at most “M x N = MN” Cell instances, which may not take up much memory, but would be better if there were fewer.

2.2> Use hidden subviews

Defining only one Cell, how do you display different types of content? The answer is to define all the different types of views, put them in the cell, and display the different types of content by hidden. After all, it’s much faster to simply show and hide a subview in a quick user swipe than to create it in real time.


3. Calculate and cache the Cell height in advance

In iOS, do not set UITableViewCell forecast line, under the condition of high priority calls “tableView: heightForRowAtIndexPath:” method, and obtain the height of each Cell will display, to determine the layout of the UITableView, Actually is to get the contentSize (UITableView inherited from UIScrollView, only get the scroll area, to achieve the rolling), and then call “tableView: cellForRowAtIndexPath”, for each Cell, carries on the assignment. If a module in a project has 10,000 cells to display, you can imagine…

Solution: In my opinion, you can create a frame model that calculates the height of each Cell in advance. Refer to one of the blog, at the time of the solution to this problem, can calculate the height of the Cell in the data model, but it has to do with the MVC design pattern may be a little conflict, this time I was thinking the MVVM design pattern, this at this time to a little MVVM the advantages of this design pattern (or really don’t understand), You can put the compute Cell height into the ViewModel and let the Model only handle the data.

Further optimizations can be made to create and cache data that is actually displayed and needs to be processed ahead of time. However, I don’t think I have been exposed to this aspect of optimization before. You can go to see this blog, in fact, this performance optimization also borrowed a lot of this article, this is the earth god’s blog address, you can go to have a look, a lot of iOS development knowledge, of course, I refer to this blog. tutuge.me


4. Asynchronous drawing (Custom Cell drawing)

When it comes to complex interfaces, such as text and text mixing, the above method of optimizing line height may not meet the requirements. Of course, due to my short development experience, to be honest, I have not encountered the need to redraw custom cells. As for this, you can refer to this blog post, which is definitely a very experienced developer, sharing enough performance optimizations for UITableView, many borrowed from here, I am embarrassed. www.cocoachina.com/ios/2015060…


5. When sliding, load as needed

In the development process, there are various types of custom cells, but the Cell is used to display data, not 100% with pictures, it is similar, this time to consider, the process of sliding may have a bit of lag, especially when the network is not good, a programmer will think, But if you add asynchronous loading to every loop object, too many threads will stall. I remember the number of threads was usually 3-5, maybe 6 at most. This time using UIScrollViewDelegate two proxy methods can be a good solution to this problem.

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollViewCopy the code

The idea is to recognize when a UITableView is disabled or when a slow slide ends, and load images asynchronously. During a fast slide, only cells within the target range are loaded on demand, which greatly improves smoothness. SDWebImage can load asynchronously, which works perfectly with this feature, especially when large numbers of images are displayed. And there’s no need to worry about memory warnings from image caching.

// Get visible parts of the Cell NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows]; For (NSIndexPath *indexPath in visiblePaths) {Copy the code

Remember the remember into “tableView: cellForRowAtIndexPath:” approach:

// tableView stops sliding when loading images asynchronously - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath) *) indexPath if (self. TableView. Dragging = = NO && self. The tableView, decelerating = = NO) {/ / asynchronous loading pictures < code >}Copy the code

6. The cache the View

If some of the views in the Cell are very independent, and not easy to reuse, and the “volume” is very small, under the premise of controllable memory, we can cache these views. It’s also cached in the model.


7. Avoid lots of zooming, color gradient, etc., and try to display “just the right size image resources”.


8. Avoid obtaining data from the network or files synchronously. The content in the Cell is from the Web, and the request result is cached asynchronously


Render 9.

9.1> Reduce the number and level of subviews

The deeper the hierarchy of child controls, the more computation is required to render to the screen; For example, use drawRect instead of view to draw elements

9.2> Use less transparent layers of Subviews

For the opaque View, set opaque to YES, so that when drawing the View, you do not need to consider other contents covered by the View. (Try to set the View of the Cell to Opaque to prevent the GPU from drawing the contents below the Cell.)

9.3> Avoid CALayer effects (shadowPath)

Shading a View in a Cell can cause performance problems, such as the following code that causes a noticeable lag in scrolling:

view.layer.shadowColor = color.CGColor;
view.layer.shadowOffset = offset;
view.layer.shadowOpacity = 1;
view.layer.shadowRadius = radius;Copy the code

Summary: Optimization of UITableView mainly starts from three aspects:

  • Calculate and cache the height (layout) in advance, because heightForRowAtIndexPath: is the most frequently called method; (This will definitely need to be optimized during development. It is impossible for an app to have several cells.)

  • Sliding loads on demand to prevent stalling, which I also think is necessary to do performance optimization, in conjunction with SDWebImage

  • Asynchronous drawing, encounter complex interface, performance bottleneck, may be a breakthrough (such as the problem, encounter complex interface, can start from this)

  • Caching everything that can be cached is often the direction of most performance optimizations during development