When self-sizing UITableView cells don't

One of the advances in iOS 8 was self-sizing UITableView cells. In earlier versions of iOS, if one wanted a table view whose cells' height varied, one had to explicitly calculate the height for each cell, providing a method which returned it; a process involving considerable string-measuring. Since iOS 8, this is no longer necessary; it is now possible to set a UITableView's rowHeight to a new magic value, UITableViewAutomaticDimension; this causes the table view to evaluate each cell's auto-layout constraints, determining its size. Of course, this means that one has to design one's custom cells in such a way that the constraints “push outwards” on the top and bottom edges of the content view, expanding it as the intrinsic sizes of the contained subviews increase. Still, that makes auto-sizing table view cells a lot simpler, especially for complex cells; in theory, at least.

This mechanism is not without its problems. There is an intermittent bug which, in some instances, causes cells to not be sized until the second time they are shown. In other words, when the cell first appears, it is in the default size it is on the storyboard, and any text that does not fit on labels is truncated. If the user scrolls the cell off the screen and then scrolls back to it, it reappears properly sized. Or, taking an example (taken from my MPDluxe MPD controller app):

The above view is a UITableView showing the contents of a directory on a music server. The left image is what appears when the user first enters the directory; while the second cell is sized correctly, the third cell is not, and the title is cut off. The right image is what appears if the user scrolls down (moving the top cells off the screen) and then scrolls back up; here, the third cell is sized properly.

Given that a second displaying operation causes the cell's size to be calculated properly, one workaround may be to force the cells to be reloaded when the view appears; i.e., adding to the view controller:

That's better; the cells that appear at the start are now sized correctly. However, if there are any mis-sized cells below the first screenful, they will still appear incorrectly sized the first time the user scrolls to them. Which means that we need something subtler than reloading the whole table view at start time.

Fortunately for us, the UITableViewDelegate protocol has an optional method titled tableView:willDisplayCell:forRowAtIndexPath:. As the name suggests, if defined, this is called just before a cell is displayed. Which would allow us to force a reload of the cell.

Which does the trick; the cells appear with the correct size now. However, scrolling is also noticeably slower. The problem is, each cell is reloaded every time it appears, whether it has been resized or not. So the next step is to add a memory of which cells have been reloaded, and not reload any cell more than once:

Of course, this is just a beginning; if the user scrolls down rapidly, it will still trigger a flurry of reloads. The next step would involve application-specific logic, checking whether a cell can be eliminated as a candidate for reloading based on model information (for example, is it a type of cell which suffers from the problem, or is the information in the model particularly long).

There are no comments yet on "When self-sizing UITableView cells don't"

Want to say something? Do so here.

Post pseudonymously

Display name:

URL:(optional)

Post using your Facebook ID

To prove that you are not a bot,please enter the text in the image on the rightin the field below it.

Your Comment:

Please keep comments on topic and to the point. Inappropriate comments may be deleted.

Note that markup is stripped from comments; URLs will be automatically converted into links.