Basem Saadawy
Basem Saadawy

Reputation: 1818

NSLayoutConstraint break within UITableViewCell

When adding a viewController.view to a table view cell programmatically with autolayout constraints it sometimes not laid out correctly. Knowing that cells have fixed height (50) and the sub view contains a UIButton and a UITableView which doesn't contain cells at the begining until the user do some action.
Here is the code that adds the sub view to the cell:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    //Get sub item objects
    BookItem * newItem = self.subItems[indexPath.row];
    NSString * newItemKey = [NSString stringWithFormat:@"%i", newItem.iD];
    NSString * currentCellItemKey = [NSString stringWithFormat:@"%i", cell.tag];
    BookTreeItemViewController_iPad * bookTreeItemVC = self.subItemVCs[currentCellItemKey];
    if (!bookTreeItemVC)
    {
        bookTreeItemVC = [self.storyboard instantiateViewControllerWithIdentifier:@"BookTreeItemViewController_iPad"];
        //Clear cell
        for (UIView * subView in cell.contentView.subviews)
            [subView removeFromSuperview];
        //Add sub item view to cell
        [bookTreeItemVC.view setTranslatesAutoresizingMaskIntoConstraints:NO];
        [cell.contentView addSubview:bookTreeItemVC.view];
        [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[item]|" options:nil metrics:nil views:@{@"item": bookTreeItemVC.view}]];
        [cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[item]|" options:nil metrics:nil views:@{@"item": bookTreeItemVC.view}]];
    }
    bookTreeItemVC.bookItem = newItem;

    //Replace the old book tree item view controller with the new one
    [self.subItemVCs setValue:nil forKey:currentCellItemKey];
    cell.tag = newItem.iD;
    self.subItemVCs[newItemKey] = bookTreeItemVC;

    return cell;
}

Here is the constraints warning:

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. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x7c091240 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7c0895d0(49.5)]>",
    "<NSLayoutConstraint:0x7a74f250 V:[UIButton:0x7a7482a0'Title']-(8)-[UITableView:0x7aad7a00]>",
    "<NSLayoutConstraint:0x7a74f2b0 V:[_UILayoutGuide:0x7a74ee70]-(0)-[UIButton:0x7a7482a0'Title']>",
    "<NSLayoutConstraint:0x7a74f310 V:[UITableView:0x7aad7a00]-(0)-[_UILayoutGuide:0x7a74ef60]>",
    "<_UILayoutSupportConstraint:0x7a739510 V:[_UILayoutGuide:0x7a74ee70(87)]>",
    "<_UILayoutSupportConstraint:0x7a74e2e0 V:|-(0)-[_UILayoutGuide:0x7a74ee70]   (Names: '|':UIView:0x7a74ee00 )>",
    "<_UILayoutSupportConstraint:0x7a747900 V:[_UILayoutGuide:0x7a74ef60(0)]>",
    "<_UILayoutSupportConstraint:0x7a748130 _UILayoutGuide:0x7a74ef60.bottom == UIView:0x7a74ee00.bottom>",
    "<NSLayoutConstraint:0x7a750c10 V:|-(0)-[UIView:0x7a74ee00]   (Names: '|':UITableViewCellContentView:0x7c0895d0 )>",
    "<NSLayoutConstraint:0x7a748270 V:[UIView:0x7a74ee00]-(0)-|   (Names: '|':UITableViewCellContentView:0x7c0895d0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7a74f250 V:[UIButton:0x7a7482a0'Title']-(8)-[UITableView:0x7aad7a00]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

By the way, I've noticed from the warning that the top layout guide has a height of (87) which supposed to be (0)

Upvotes: 1

Views: 1000

Answers (3)

Basem Saadawy
Basem Saadawy

Reputation: 1818

After two days of research I had to remove the table view of the sub view (The view that's put into the cell) from the IB (storyboard) and add it programmatically with its constraints. So, Every thing is ok now.

Upvotes: 0

Peter
Peter

Reputation: 1109

Yes, you are right.

"<_UILayoutSupportConstraint:0x7a739510 V:[_UILayoutGuide:0x7a74ee70(87)]>",

Somehow, your view controller has layout guide with top supporting value of 87. This crash with your fixed cell height, hence it is removing the constraint of distance between button and tableview.

Maybe you can post your layout code of the BookTreeItemViewController_iPad or

  • try 3D debugging from new xcode to find out what is that 87 pixel ?
  • set your TableView.rowHeight to UITableViewAutomaticDimension, so that your cell height will be dynamic. Then, again, you can see what is that 87 pixels.

Upvotes: 1

Hussain Shabbir
Hussain Shabbir

Reputation: 15015

The issue looks like when you are removing the view, your constraint is not getting removed. So just replace the below code:-

Replace :-

for (UIView * subView in cell.contentView.subviews)
 [subView removeFromSuperview];

TO:-

[cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];     

And also modiified the below in a more efficient way :-

NSView *views=bookTreeItemVC.view;
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[item]|" options:0l metrics:nil views:NSDictionaryOfVariableBindings(views)]];
[cell.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[item]|" options:0l metrics:nil views:NSDictionaryOfVariableBindings(views)]];

Upvotes: 0

Related Questions