Note that there are some explanatory texts on larger screens.

plurals
  1. POUITableViewHeaderFooterView subclass with auto layout and section reloading won't work well together
    primarykey
    data
    text
    <p>I am trying to incorporate auto layout into my UITableViewHeaderFooterView subclass. The class is pretty basic, just two labels. This is the complete subclass: </p> <pre><code>@implementation MBTableDetailStyleFooterView static void MBTableDetailStyleFooterViewCommonSetup(MBTableDetailStyleFooterView *_self) { UILabel *rightLabel = [[UILabel alloc] init]; _self.rightLabel = rightLabel; rightLabel.translatesAutoresizingMaskIntoConstraints = NO; [_self.contentView addSubview:rightLabel]; UILabel *leftLabel = [[UILabel alloc] init]; _self.leftLabel = leftLabel; leftLabel.translatesAutoresizingMaskIntoConstraints = NO; [_self.contentView addSubview:leftLabel]; NSDictionary *views = NSDictionaryOfVariableBindings(rightLabel, leftLabel); NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-10-[leftLabel]-(&gt;=10)-[rightLabel]-10-|" options:0 metrics:nil views:views]; [_self.contentView addConstraints:horizontalConstraints]; // center views vertically in super view NSLayoutConstraint *leftCenterYConstraint = [NSLayoutConstraint constraintWithItem:leftLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; [_self.contentView addConstraint:leftCenterYConstraint]; NSLayoutConstraint *rightCenterYConstraint = [NSLayoutConstraint constraintWithItem:rightLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_self.contentView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; [_self.contentView addConstraint:rightCenterYConstraint]; // same height for both labels NSLayoutConstraint *sameHeightConstraint = [NSLayoutConstraint constraintWithItem:leftLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:rightLabel attribute:NSLayoutAttributeHeight multiplier:1 constant:0]; [_self.contentView addConstraint:sameHeightConstraint]; } + (BOOL)requiresConstraintBasedLayout { return YES; } - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithReuseIdentifier:reuseIdentifier]; MBTableDetailStyleFooterViewCommonSetup(self); return self; } @end </code></pre> <p>This class is used as a footer in the first section in a tableView with 2 sections. The first section contains dynamic items. The second section has only one row, which is used to add new items to the first section. </p> <p>If there are no items in the first section I hide the footerView. So when I add the first new item I have to reload the section so the footerView appears. The code that does all this looks like this:</p> <pre><code>- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; if (indexPath.section == 1) { BOOL sectionNeedsReload = ([self.data count] == 0); // reload section when no data (and therefor no footer) was present before the add [self.data addObject:[NSDate date]]; NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:[self.data count]-1 inSection:0]; if (sectionNeedsReload) { [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationAutomatic]; } else { [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; } [self configureFooter:(MBTableDetailStyleFooterView *)[tableView footerViewForSection:0] forSection:0]; } } - (void)configureFooter:(MBTableDetailStyleFooterView *)footer forSection:(NSInteger)section { footer.leftLabel.text = @"Total"; footer.rightLabel.text = [NSString stringWithFormat:@"%d", [self.data count]]; } - (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section { MBTableDetailStyleFooterView *footer = nil; if (section == 0 &amp;&amp; [self.data count]) { footer = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"Footer"]; [self configureFooter:footer forSection:section]; } return footer; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { CGFloat height = 0; if (section == 0 &amp;&amp; [self.data count]) { height = 20.0f; } return height; } </code></pre> <p>Nothing really fancy. However, <strong>as soon as <code>reloadSections:withRowAnimations:</code> is called on my tableView it throws an exception because it is "Unable to simultaneously satisfy constraints.".</strong> </p> <p>Somewhere the tableView added a translated auto resizing mask constraint to my footer. </p> <pre><code>( "&lt;NSLayoutConstraint:0x718a1f0 H:[UILabel:0x7189130]-(10)-| (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )&gt;", "&lt;NSLayoutConstraint:0x7189e30 H:[UILabel:0x71892c0]-(&gt;=10)-[UILabel:0x7189130]&gt;", "&lt;NSLayoutConstraint:0x718a0a0 H:|-(10)-[UILabel:0x71892c0] (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )&gt;", "&lt;NSAutoresizingMaskLayoutConstraint:0x7591ab0 h=--&amp; v=--&amp; H:[_UITableViewHeaderFooterContentView:0x7188df0(0)]&gt;" ) </code></pre> <p>When I replace <code>reloadSections:withRowAnimations:</code> with a call to <code>reloadData</code> no autoresizing mask constraint is added and everything works fine. </p> <p>The interesting thing is that the exception tells me that it tries to break the constraint <code>&lt;NSLayoutConstraint:0x7189e30 H:[UILabel:0x71892c0]-(&gt;=10)-[UILabel:0x7189130]&gt;</code></p> <p>But when I log the constraints in subsequent calls to <code>configureFooter:forSection:</code> this constraint still exists, but the auto resizing mask constraint is gone</p> <p>The constraints are exactly those that I have set up. </p> <pre><code>( "&lt;NSLayoutConstraint:0x718a0a0 H:|-(10)-[UILabel:0x71892c0] (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )&gt;", "&lt;NSLayoutConstraint:0x7189e30 H:[UILabel:0x71892c0]-(&gt;=10)-[UILabel:0x7189130]&gt;", "&lt;NSLayoutConstraint:0x718a1f0 H:[UILabel:0x7189130]-(10)-| (Names: '|':_UITableViewHeaderFooterContentView:0x7188df0 )&gt;", "&lt;NSLayoutConstraint:0x718a3f0 UILabel:0x71892c0.centerY == _UITableViewHeaderFooterContentView:0x7188df0.centerY&gt;", "&lt;NSLayoutConstraint:0x718a430 UILabel:0x7189130.centerY == _UITableViewHeaderFooterContentView:0x7188df0.centerY&gt;", "&lt;NSLayoutConstraint:0x718a4b0 UILabel:0x71892c0.height == UILabel:0x7189130.height&gt;" ) </code></pre> <p>Where does this auto resizing mask constraint come from? Where does it go? </p> <p>Am I missing something? The first time I looked into auto layout was like a week ago, so this is totally possible.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload