title: Autolayout + UITableView generates phantom section headers on iOS 6
body: <p>So I inherited a project with some code in it, that kind of behaves like iMessage.</p>
  
  <p><img src="https://i.stack.imgur.com/a0LmZ.png" alt="enter image description here"></p>
  
  <p>There are two view here, the top one which goes from the navigation bar to the compose message one and the bottom one which is the compose message at the bottom.</p>
  
  <p>The compose message one is supposed to grow in height, whenever the text entered spans on more than one line, so on showing of the keyboard the following autolayout rules are set on the container view:</p>
  
  <pre><code> NSDictionary *viewsToConstrain = NSDictionaryOfVariableBindings(bottomView, topView);
      _vConstraints = [NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:|[topView]-(0)-[bottomView]-(==%.1f)-|", keyboardHeight]
                                                              options:NSLayoutFormatAlignAllCenterX
                                                              metrics:nil
                                                                views:viewsToConstrain];
  </code></pre>
  
  <p>So as you type away in that compose text view, the compose box grows bigger and the tableView that has the messages grows smaller, like so:</p>
  
  <p><img src="https://i.stack.imgur.com/3rT3I.png" alt="enter image description here"></p>
  
  <p>Whenever you click on the send button, a Message entity is created and stored in CoreData. The view controller that hosts the table view and the compose message view has a fetched results controller that adds the newly created message to the table view with some standard UITableView animation:</p>
  
  <pre><code>- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
  {
          [self.tableView beginUpdates];
  }
  </code></pre>
  
  <hr>
  
  <pre><code>- (void)controller:(NSFetchedResultsController *)controller
     didChangeObject:(id)anObject
         atIndexPath:(NSIndexPath *)indexPath
       forChangeType:(NSFetchedResultsChangeType)type
        newIndexPath:(NSIndexPath *)newIndexPath
  {
  
          switch (type)
          {
              case NSFetchedResultsChangeInsert:
  
                      [self.tableView insertRowsAtIndexPaths:@[newIndexPath]
                                            withRowAnimation:UITableViewRowAnimationTop];
  
                  break;
  
                  ...
                  // Handle all the other cases
          }
  }
  </code></pre>
  
  <hr>
  
  <pre><code>- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
  {
      [self.tableView endUpdates];
  }
  </code></pre>
  
  <p>And it all works ok.
  Now whenever the message is long enough, the compose view gets so tall that the table view's height becomes 0.</p>
  
  <p><img src="https://i.stack.imgur.com/uyJrV.png" alt="enter image description here"></p>
  
  <p>Whenever the Send button is pressed in this state, the </p>
  
  <pre><code>- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
  </code></pre>
  
  <p>method on the table view gets called and a new header is added, even though the</p>
  
  <pre><code>- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
  </code></pre>
  
  <p>method returns a correct number of headers (in this case 1) and a second header is added, even though it shouldn't have been.</p>
  
  <p><img src="https://i.stack.imgur.com/CRbBk.png" alt="enter image description here"></p>
  
  <p>As you can see it actually is placed on top of one of the cells and it partially obscures that cell.</p>
  
  <p>And it doesn't really behave like a header, as it doesn't push away the top header, but instead goes beneath it, like so:</p>
  
  <p><img src="https://i.stack.imgur.com/Kw75c.png" alt="enter image description here"></p>
  
  <p>It's really weird, because it all works fine whenever the table view's height doesn't reach 0 and it works on iOS 7 even then.</p>
  
  <p>And if I take away the animation, by removing <code>beginUpdates</code>  <code>endUpdates</code> and replacing <code>insertRowsAtIndexPaths:withRowAnimation:</code> with <code>reloadData</code> - it all works fine on iOS 6 as well.</p>
  
  <p>So bottom line: using autolayout to make a tableView smaller somehow makes it think that it should have more sections than it does, it doesn't recycle the old section header view and inserts a phantom header that doesn't behave like a section header and it shouldn't be inserted in there.</p>
  
  <p>I've implemented my solution on iOS6 and iOS 7 works ok, but I'd really like to know why this happens.</p>
  
  <p>Any ideas?</p>
  
  <p>Edit:</p>
  
  <p>Here's the implementation for  <code>viewForHeaderInSection</code></p>
  
  <pre><code>- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
  {
      UITableViewHeaderFooterView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:kSectionHeaderXibIdentifier];
      UILabel *textLabel = (UILabel *)[view viewWithTag:kSectionHeaderTextTag];
      if (!textLabel)
      {
          // we have no subviews yet, so create them
  
          view.contentView.backgroundColor = [UIColor whiteColor];
  
          textLabel = [UILabel autoLayoutView];
          textLabel.tag = kSectionHeaderTextTag;
          textLabel.backgroundColor = [UIColor clearColor];
          [view.contentView addSubview:textLabel];
  
          UIView *leftArt = [UIView autoLayoutView];
          leftArt.backgroundColor = kSectionOrnamentColor;
          [view.contentView addSubview:leftArt];
  
          UIView *rightArt = [UIView autoLayoutView];
          rightArt.backgroundColor = kSectionOrnamentColor;
          [view.contentView addSubview:rightArt];
  
          NSDictionary *bindingViews = NSDictionaryOfVariableBindings(textLabel, leftArt, rightArt);
  
          NSString *horzFormat = @"H:|-(12)-[leftArt(&gt;=0)]-(8)-[textLabel]-(8)-[rightArt(leftArt)]-(12)-|";
          [view.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:horzFormat
                                                                                  options:0
                                                                                  metrics:nil
                                                                                    views:bindingViews]];
  
          [view.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(28.)-[leftArt(1)]-(&gt;=0)-|"
                                                                                   options:0 metrics:nil views:bindingViews]];
  
          [textLabel pinToSuperviewEdges:JRTViewPinTopEdge inset:14.];
          [rightArt pinAttribute:NSLayoutAttributeTop toSameAttributeOfView:leftArt];
          [rightArt pinAttribute:NSLayoutAttributeHeight toSameAttributeOfView:leftArt];
      }
  
      textLabel.attributedText = [self titleForHeaderInSection:section];
  
      [textLabel invalidateIntrinsicContentSize];
      [view.contentView needsUpdateConstraints];
  
      return view;
  }
  </code></pre>
  
  <p>We get the default header view and add some subviews on top of that.</p>