I am trying to debug a crash due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSFrozenDictionary layoutSublayers]: unrecognized selector sent to instance.
I see 2 things that I find interesting about it.
- The fact that the instance is a
__NSFrozenDictionary
tells me that the reference to aCALayer
that has since been evicted from memory and re-written. - The call to
layoutSublayers
tells me that theCALayer
was dealloc-ed at some point between the call tosetNeedsLayout
(orlayoutIfNeeded
)
This seemingly occurs as part of a call to -[UITableView reloadData]
Furthermore, each cell created by the UITableView
has a UIStackView
.
- As part of the call to
cellForRowAtIndexPath
the code adds an instance of "custom view" to the stack view's subviews. - As part of the call to
prepareForReuse
the code removes the "custom view" from the stack view's subviews.
Therefore as part of the prepareForReuse
the "custom view" (and its layer) is evicted from memory.
My theory is that the tableview does a layout pass on the visible cell which has since had its subview removed which causes the crash.
My question is what are the constraints on when/where to call reloadData and/or when/where you should definitely avoid it as it relates to this context?
This is code that modifies the view hierarchy of the cell as part of its lifecycle which AFAIK this is "not supported" since prepareForReuse
is meant to be used for resetting view state and cellForRowAtIndexPath
to reset content.
In that sense, another question, are you not allowed to modify the cell view hierarchy period as part of the cycle to draw the visible cells or is it more of a case, do not call reloadData
?
reloadData throw all of the views/cells away, and re-create everything. UITableView cannot track the identity of sections or items across reloadData, it’s a complete reset.
So general you don’t want to call reloadData if you can help it. Ideally you'll want to use a combination of UITableViewDiffableDataSource which handles automatically diffing sections & items for you, and generating the correct batch updates on the UITableView) + your own change detection for properties within existing items so you can call the reconfigure or reload APIs on the diffable snapshot as needed, to update content within existing views.