1

In my project targeting iOS 8 I have a UITableView with automatic, variable row height. In the storyboard I have defined one prototype UITableViewCell with most constraints set up. Since the cell content can vary slightly based on the object it's going to display, I decided not to create several prototypes in the storyboard and instead do the necessary changes programmatically. I'm adding any missing cell subviews inside of tableView(_:cellForRowAtIndexPath).

What is causing me problems is creating the missing constraints. This is not possible in tableView(_:cellForRowAtIndexPath) since the cell subviews are not set up yet (i.e. they don't have a superview yet), so instead I call cell.setNeedsUpdateConstraints() and set them up inside the cell.updateConstraints() override. This approach mostly works, except for the following case. The table view has a selection segue pushing a view controller onto the navigation stack; then inside the action method triggered by the unwind segue I want to reload the cell for the row which triggered the selection segue, but calling tableView.cellForRowAtIndexPath(_) either raises this exception inside cell.updateConstraints():

The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0x7aa950b0 V:[UITextView:0x7b3d2e00'Fasd']-(8)-[UIButton:0x7aa860c0'0 comments']>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView(UIConstraintBasedLayout) _viewHierarchyUnpreparedForConstraint:] to debug.

or this warning:

Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view. We're considering the collapse unintentional and using standard height instead.

which effectively causes some of the cells to have the estimated row height and their subviews all messed up.

It seems like in this special case, the cell subviews have not yet been set up. Does anybody know a solution to this problem?

Nickkk
  • 2,261
  • 1
  • 25
  • 34
  • How are you adding these constraints? You should be using the cell content view property, not the cell itself to add constraints. Also be careful if cells are dequeued (reused) you need to remove previous constraints before adding the new ones since a dequeued cell will already contain previously added constraints. – Matic Oblak Jan 18 '17 at 13:29
  • You should never call `tableView.cellForRowAtIndexPath(_)` yourself. If you want to reload a specific row, you should call `reloadRows(at indexPaths: [IndexPath], with animation: UITableViewRowAnimation)` on your `UITableView` object. – mattsson Jan 18 '17 at 13:29
  • Also this is a bad approach. If the cells are similar in data but have a different layout it is still better to make a cell for each layout in the storyboard. You can still use only 1 subclass to connect the outlets to but you need a different identifier for each cell (which is a good thing in your case). – Matic Oblak Jan 18 '17 at 13:33
  • I'm adding the constraints to the cell content view only once by keeping track of them with an instance variable. And `reloadRowsAtIndexPaths(_:withRowAnimation:)` raises the same exception. – Nickkk Jan 18 '17 at 14:50

0 Answers0