Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsatisfiable constraints with NSTableView when calling reloadData

I have a view-based NSTableView with the table view's NSTableCellView's setup graphically through interface builder in the latest version of Xcode on 10.8.2.

When I call -reloadData on the NSTableView, it crashes with:

Unable to simultaneously satisfy constraints:
(
    "<NSAutoresizingMaskLayoutConstraint:0x105cb8bf0 h=--& v=--& V:[NSTableRowView:0x105ca7020(0)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x10596aa30 h=--& v=-&- V:[GroupTableRowView]-(2)-|   (Names: GroupTableRowView:0x100185860, '|':NSTableRowView:0x105ca7020 )>",
    "<NSAutoresizingMaskLayoutConstraint:0x1058d9770 h=--& v=-&- V:|-(1)-[GroupTableRowView]   (Names: GroupTableRowView:0x100185860, '|':NSTableRowView:0x105ca7020 )>"
)

Will attempt to recover by breaking constraint 
<NSAutoresizingMaskLayoutConstraint:0x10596aa30 h=--& v=-&- V:[GroupTableRowView]-(2)-|   (Names: GroupTableRowView:0x100185860, '|':NSTableRowView:0x105ca7020 )>

I can't turn off auto-resizing mask translation on any of the views involved as their constraints are managed by the NSTableView. It's clear that the constraints are conflicting because the NSTableRowView can't possibly have a 0 height while still satisfying the other two constraints on the GroupTableRowView that specify mandatory padding between the superview (the row view?). I'm not sure how to resolve this, any insights would be greatly appreciated. Thanks!

Update: I found a workaround. The issue is that for some reason the NSTableRowView was being sent a frame size of {0, 0} when calling -reloadData on the table view. I overrode -setFrameSize: in the NSTableRowView subclass and only pass the message up the responder chain when the size is not {0,0}.

- (void)setFrameSize:(NSSize)newSize
{
    if (!NSEqualSizes(newSize, NSZeroSize))
        [super setFrameSize:newSize];
}

To use the subclass, implement NSTableViewDelegate's -tableView:rowViewForRow: method to return an instance of the custom subclass.

- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row
{
    id rowView = [[GroupTableRowView alloc] init];
    // configure any custom properties
    return rowView;
}

If the table view is designed entirely in IB, you can simply drag a new NSView into your table view and set it's custom class to your NSTableRowView subclass and change it's User Interface Item Identifier to NSTableViewRowViewKey

like image 949
Andrew Avatar asked Jan 04 '13 21:01

Andrew


2 Answers

I had the same issue and it always drove me nuts..

I've solved it using your code, but subclassing NSTableRowView instead of NSTableCellView. To automatically let the table use your custom row view, add a custom NSView into your table. Set its class to your custom row view and, important, its identifier to NSTableViewRowViewKey.

With this special identifier, the table automatically uses it as a row view.

like image 149
paxos Avatar answered Oct 17 '22 09:10

paxos


I had a similar issue, but with column width rather than row height. Unsatisfiable autolayout constraints were popping up on the cells of view-based NSTableViews immediately after reloadData was called. In my case, it was caused by the minimum width setting on the NSTableColumn being too small to contain the minimum width for the constraints in the cell. So for anyone with a similar problem, I would first verify that.

The "interesting" part was that this was only an issue for reloadData, not for normal layout, because there were constraints on the width of the NSTableView that prevented it from normally ever attempting to create a cell that small. But when reloadData was called, it apparently first creates a new cell with its frame size set to the minimum column width, before later resizing the column to fit properly (if you have the table set to do that). So even though everything appeared to work fine, it would still spit out the error about unsatisfiable constraints right after reloadData was called, because the initial width of the cell view was too small for the padding, etc.

Moral of the story is to always check that the minimum NSTableColumn width is big enough for the constraints in the cell, even if you don't think the column will ever be that small. IB makes it easy to tinker with the constraints, and it's easy to forget to recheck the column width options after changing something in the cells.

like image 32
mnemia Avatar answered Oct 17 '22 08:10

mnemia