I'm getting a layout constraint error for a UILable in a UITableViewCell. My app is a to do list, and I have a UITableView that contains UITableViewCells of varying heights. If I drag a cell down to the bottom slowly and the page starts to scroll, I get the error. see video of error condition
Here is the error I am getting:
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
2022-03-12 11:18:28.445423-0800 Action[83734:5205929] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x600003361590 V:|-(14)-[UILabel:0x1541a05d0] (active, names: '|':UITableViewCellContentView:0x15419ef60 )>",
"<NSLayoutConstraint:0x600003361680 V:[UILabel:0x1541a05d0]-(14)-| (active, names: '|':UITableViewCellContentView:0x15419ef60 )>",
"<NSLayoutConstraint:0x600003361bd0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x15419ef60.height == 0 (active)>"
)
I set a symbolic breakpoint as suggested and get this additional info (4th line has "AMBIGUOUS LAYOUT"):
| | | | | | | *<UILayoutGuide: 0x600003f7c380 - "UIViewSafeAreaLayoutGuide", layoutFrame = {{0, 94}, {375, 684}}, owningView = <UIView: 0x132006ea0; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x600000679480>>>
| | | | | | | *UIView:0x132007010
| | | | | | | | *UITableView:0x13300c000
| | | | | | | | | *<UIFocusContainerGuide: 0x60000396c4b0 - "UITableViewContentFocusContainerGuide", layoutFrame = {{0, 0}, {375, 684}}, owningView = <UITableView: 0x13300c000; frame = (0 0; 375 684); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x6000008dc5a0>; layer = <CALayer: 0x6000006597e0>; contentOffset: {0, 0}; contentSize: {375, 2783.9999949137377}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <Action.ProjectController: 0x130e085e0>>>- AMBIGUOUS LAYOUT for UIFocusContainerGuide:0x60000396c4b0'UITableViewContentFocusContainerGuide'.minX{id: 3169}, UIFocusContainerGuide:0x60000396c4b0'UITableViewContentFocusContainerGuide'.minY{id: 3170}, UIFocusContainerGuide:0x60000396c4b0'UITableViewContentFocusContainerGuide'.Width{id: 3171}, UIFocusContainerGuide:0x60000396c4b0'UITableViewContentFocusContainerGuide'.Height{id: 3172}
| | | | | | | | | Action.ActionCellView:0x12f0a1600'ReusableCell'
| | | | | | | | | | _UISystemBackgroundView:0x12de973f0
| | | | | | | | | | | UIView:0x12de95f90
| | | | | | | | | | •UITableViewCellContentView:0x12de962a0
| | | | | | | | | | | *UIButton:0x12de96440
| | | | | | | | | | | | _UISystemBackgroundView:0x12de968e0
| | | | | | | | | | | | UIImageView:0x12de96700
| | | | | | | | | | | *UILabel:0x12de96aa0
| | | | | | | | | | _UITableViewCellSeparatorView:0x12de97080
| | | | | | | | | | _UITableViewCellSeparatorView:0x12de99c70
| | | | | | | | | | _UITableViewCellSeparatorView:0x1309081d0
Here is how I have set up the table view in my controller's viewDidLoad:
tableView.register(UINib(nibName: K.Action.cellNibName, bundle: nil), forCellReuseIdentifier: K.Action.cellIdentifier)
tableView.dataSource = self
tableView.dragDelegate = self
tableView.dropDelegate = self
tableView.delegate = self
tableView.showsVerticalScrollIndicator = false
Here is the UITableViewDataSource implementation:
extension ProjectController: UITableViewDataSource {
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.rowHeight
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let project = model.projects.data[projectId!] {
return project.actionIds.count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: K.Action.cellIdentifier, for: indexPath) as! ActionCellView
if let project = model.projects.data[projectId!] {
let actionId = project.actionIds[indexPath.row]
let action = model.actions.data[actionId]!
cell.titleLabel.text = action.title
cell.delegate = self
cell.actionId = actionId
if action.scheduled != nil {
cell.label = action.scheduled!.toString()
}
}
return cell
}
}
I've also implemented UITableViewDragDelegate:
extension ProjectController: UITableViewDragDelegate {
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
let dragItem = UIDragItem(itemProvider: NSItemProvider())
return [ dragItem ]
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let project = model.projects.data[projectId!]!
let actionId = project.actionIds[sourceIndexPath.row]
model.moveAction(actionId, inProject: projectId!, toRank: destinationIndexPath.row)
}
}