I have a view controller that contains a table view and displays custom cells. I’m trying to react to a content size category change using the traitCollectionDidChange
method (within the cell subclass), but this method is never called for the cells when this trait changes. On the other hand, it does get called when the size class changes.
traitCollectionDidChange
is called for the view controller (when the content size category changes) and I can manually propagate the call to the visible cells, but it feels like extra work. Why is it not getting called for the cell subclasses specifically for the content size category change?
Edit for reasoning why I want the call within the cell:
I want to change the cell’s label to multi-line when the content size category is associated with accessibility, but keep it single-line otherwise. I’ve noticed this behavior in certain iOS apps, e.g. Apple Music.
2
Answers
Any place in your app that needs to hear about content size category changes can register for the
UIContentSizeCategory.didChangeNotification
.https://developer.apple.com/documentation/uikit/uicontentsizecategory/1622948-didchangenotification
So instead of you propagating the information down the hierarchy, just have an appropriate object register for that notification. For example, perhaps you have (or could have) a custom table view cell subclass where this would be appropriate.
As for the question you actually asked, all I can do is provide a theory. Apple configures things like a UILabel to receive
UIContentSizeCategory.didChangeNotification
when it is in a table view cell. This involves some hanky-panky behind the scenes. I suspect that as part of this hanky-panky, they deliberately prevent the cell itself from receivingtraitCollectionDidChange
for content size category changes, since the same signal is arriving already in a different way and they don’t want to bombard the cell contents with too many events.A surprising detail about a UITableViewCell lifecycle:
changes in size class cause a call to traitCollectionDidChange(_:)
changes in size category recycle the cell, and traitCollectionDidChange(_:) is not called
Therefore, changing the layout in response to size class and category needs code in two places:
You can confirm that the cell is recycled with a breakpoint in the delegate method
tableView(_:willDisplay:forRowAt:)
, and also by noting that previous constraints conditionally set for the category disappear (because the cell is removed from its superview).