Experiment the UILabel optimisation advice by Rony Fadel

This blog post has been going viral for the past weeks in iOS community. It talks about potential iOS performance optimisations, backed by sound technical argument.

One of the optimisations talks about UILabel in UITableViewCell/UICollectionViewCell. You can read the original blog for detail, but here is the gist :

  • Internally, UILabel is just a bitmap. Thus, it is more costly than you would think.
  • It is even more costly when the UILabel cannot be rendered in monochrome, e.g., using attributedText.
  • It could save you megabytes by nilifying labels’ text when you don’t need them. (Specifically in tableView(_:didEndDisplaying:forRowAt:) or
    collectionView(_:didEndDisplaying:forItemAt:)
    )

But on the other hand, the last bullet point made a target for quite a few controversy/arguments such as here, and here.

So, just for fun, I decided to run some tests to get my own feeling about it.

My setup is very simple. I created a simple table view application with one label in each cell. In order to see the effect of memory, I made the text pretty long. Like this :

Switching on “Nil out …” switch will run the advice to nilify the text in tableView(_:didEndDisplaying:forRowAt:) . “Attributed labels” switch will change the labels text to attributedTextin red color.

I ran my program on Instruments and measured how much the resident memory (physical memory consumption) changed after scrolling all the way down. As advised in the original article, I “Simulate Memory Warning” before reading the actual/stable number.

In the above example, with simple UILabel (no attributed text) without any optimisation, it started with 6.34MB before scrolling, ended with 6.59MB after scrolling. So, the action of showing the entire contents of the table and coming back to the original state caused 0.25MB (250KB) increase in physical memory footprint.

I ran the experiment with

  • Simple UILabel without any optimisation
  • Simple UILabel with nilifying optimisation
  • UILabel with attributedText
  • UILabel with attributedText with nilifying optimisation

A note is that I did it just for fun to get a ball park feeling myself, so I didn’t make stats. The results are just from a single run.

Here are the results :

Indeed nilify takes some effect, but not by much. The sample code has 192 rows, and the difference is mere 40KB~230KB. What surprised me was that Attributed Label didn’t increase memory foot stamp by much 🤔

What I tried next was to actually cache all the labels as in the following code:

It is definitely an anti-pattern that throws away the benefit of cell reuse that UITableView offers. But 1. I have seen such code before 2. I wanted to see how much actually the ~200 UILabel instances contribute to the memory footprint.

The result is as follows (New results are row 3 and row 6):

Here again, Attributed Label makes it bigger, but not by much 🤔 But it’s fair to say that ~200 UILabels increased the memory footprint more than 5MB (~25KB per label). Is it bigger or smaller than you expected?

Next, I tried to bring in UIImageView for comparison. I created exactly same table views with UIImageViews of similar size as the UILabels we implemented before:

And ran the same experiments (New results are in the bottom 3 rows):

Even with UIImageViews, the cell reuse mechanism clears the memory very well, so you don’t have to worry about memory increase at least in this case. If we cache UIImageViews, then it will increase almost 8MB of memory with ~200 images (~40KB per image), so it is a big deal. The memory footprint difference between UILabel(~25KB) and UIImage(~40KB) would have looked too small for my naive eyes if I didn’t know that UILabel is stored as bitmap internally. But the difference between monochrome and color of UILabel was not very visible in my experiment 🤔

Summary

  • Nilifying UILabel does probably not take any effect on simple cases like this. (and probably for many complex cases as well)
  • As described in the original article, UILabel internally may occupy more memory than you would expect
  • Caching contents of the UITableView/UICollectionView is very bad for memory :D
  • My code for this experiment is located in [github].

Coding in Swift, want to learn Flutter, a Dad, a Rock Climber, learning Parkour and Guitar