dequeueReusableCell(withIdentifier:) leads to inaccurate 65536 pt intrinsic width for zero-line labels with Auto Layout constraints

Originator:JackGeorgeMarch
Number:rdar://FB8321870 Date Originated:08/09/2020
Status:Open Resolved:
Product:UIKit Product Version:iOS 13.6
Classification: Reproducible:
 
UITableView's dequeueReusableCell(withIdentifier:) has a bug when the contentView has a label with the following attributes:

1. Number of lines to zero
2. Auto Layout constraints

In this case, if you try to get the label's intrinsic size, after a certain number of cells the width always returns 65536. This number is 1 more than the maximum value for a UInt16, 65535, but the maximum value of a CGFloat is a lot more so this may just be a strange coincidence.

I've found you can make the cell's label return an accurate intrinsic size if you call systemLayoutSizeFittingSize on the cell. However, in the "High Performance Auto Layout talk", Apple engineer Kasia Wawer advises against calling this frequently, saying "each time you call this method an engine is being created and discarded. While this is fine for small uses, if you're doing it a lot you can see how it might start to build up over time. So be cautious when calling System Layout Size Fitting Size." So this workaround is not ideal.

Steps to reproduce (I have experienced this on iOS 13.6 and iOS 14 beta, though I imagine it affects other versions):
1. Make a UITableViewCell subclass
2. Add a label as a subview to its content view
3. set the number of lines on the label to zero
4. Add constraints from label to content view (in the example project attached I use top, leading, bottom, trailing so height is not ambiguous, but adding just one constraint seems to lead to same bug e.g. one bottom constraint)
5. Register this cell to the tableview with a reuse identifier
6. in tableView(_:cellForRowAt:) dequeue the cell with this reuse identifier and cast it to your custom cell subclass
7. Print the label's intrinsic size in (_:cellForRowAt:)
8. Set tableView(_:numberOfRowsInSection:) to 1000 (this is an arbitrary number, but on my computer I've found the bug only occurs on cells past 66, perhaps because it starts dequeuing cells instead of making new references, so 1000 should be easily enough to reproduce the bug).
9. Run the app and watch 

Expected results
Intrinsic size to be accurate, as the size is intrinsic so dequeueReusableCell(withIdentifier:) in theory should not have any effect on it. In my project, it should be 41.5 points wide, 20.5 points high.

What you actually saw:
The intrinsic width of the label becomes 65536.0 as you scroll the tableview, in my case after 66 cells.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!