title: Adding longpress gesture on moving uitableviewcells between sections
body: <p>Following on from my earlier question 
  <a href="https://stackoverflow.com/questions/28637660/moverowatindexpath-moving-cells-between-sections">moveRowAtIndexPath - Moving cells between sections</a></p>
  
  <p>I have been able to do a traditional <code>moveRowAtIndexPath</code> for moving cells between sections, ie: Move Mark from Sales to Marketing.  </p>
  
  <p>However now I would like to go one step further and add longpress gesture on the tableview and allow me to move cells from simply using longpress on a cell.</p>
  
  <p>As a reference, my table is a list of <code>Employees</code> who work in different <code>Departments</code>; where the models are custom, but just hold simple strings for names.</p>
  
  <p>My row set up is this;</p>
  
  <pre><code>-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
  {
      return [_objects count];
  }
  
  -(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  {
      Department *department = [_objects objectAtIndex:section];
      return [department.employees count];
  }
  </code></pre>
  
  <p>My current moveRowAtIndexPath is:</p>
  
  <pre><code>- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
  {
      if (fromIndexPath != toIndexPath ) {
  
          Department *departmentFrom = [_objects objectAtIndex:fromIndexPath.section];
          Department *departmentTo = [_objects objectAtIndex:toIndexPath.section];
  
          Employee *employee = [departmentFrom.employees objectAtIndex:fromIndexPath.row];
  
          [departmentFrom.employees removeObjectAtIndex:fromIndexPath.row];
          [departmentTo.employees insertObject:employee atIndex:toIndexPath.row];
          [tableView reloadData];
      }
  }
  </code></pre>
  
  <p>So now I add longpress to the table during viewDidLoad, ala;</p>
  
  <pre><code>UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognized:)];
  [self.tableView addGestureRecognizer:longPress];
  </code></pre>
  
  <p>Then finally have my longpress code itself;</p>
  
  <pre><code>- (IBAction)longPressGestureRecognized:(id)sender {
  
      UILongPressGestureRecognizer *longPress = (UILongPressGestureRecognizer *)sender;
      UIGestureRecognizerState state = longPress.state;
  
      CGPoint location = [longPress locationInView:self.tableView];
      NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
  
      static UIView       *snapshot = nil;        ///&lt; A snapshot of the row user is moving.
      static NSIndexPath  *sourceIndexPath = nil; ///&lt; Initial index path, where gesture begins.
  
      switch (state) {
          case UIGestureRecognizerStateBegan: {
              if (indexPath) {
                  sourceIndexPath = indexPath;
  
                  UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
  
                  // Take a snapshot of the selected row using helper method.
                  snapshot = [self customSnapshoFromView:cell];
  
                  // Add the snapshot as subview, centered at cell's center...
                  __block CGPoint center = cell.center;
                  snapshot.center = center;
                  snapshot.alpha = 0.0;
                  [self.tableView addSubview:snapshot];
                  [UIView animateWithDuration:0.25 animations:^{
  
                      // Offset for gesture location.
                      center.y = location.y;
                      snapshot.center = center;
                      snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05);
                      snapshot.alpha = 0.98;
                      cell.alpha = 0.0;
  
                  } completion:^(BOOL finished) {
  
                      cell.hidden = YES;
  
                  }];
              }
              break;
          }
  
          case UIGestureRecognizerStateChanged: {
              CGPoint center = snapshot.center;
              center.y = location.y;
              snapshot.center = center;
  
              // Is destination valid and is it different from source?
              if (indexPath &amp;&amp; ![indexPath isEqual:sourceIndexPath]) {
  
                  // ... update data source.
  
                  // ... move the rows.
                  [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];
  
                  // ... and update source so it is in sync with UI changes.
                  sourceIndexPath = indexPath;
              }
              break;
          }
  
          default: {
              // Clean up.
              UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:sourceIndexPath];
              cell.hidden = NO;
              cell.alpha = 0.0;
  
              [UIView animateWithDuration:0.25 animations:^{
  
                  snapshot.center = cell.center;
                  snapshot.transform = CGAffineTransformIdentity;
                  snapshot.alpha = 0.0;
                  cell.alpha = 1.0;
  
              } completion:^(BOOL finished) {
  
                  sourceIndexPath = nil;
                  [snapshot removeFromSuperview];
                  snapshot = nil;
  
              }];
  
              break;
          }
      }
  }
  
  #pragma mark - Helper methods
  
  /** @brief Returns a customized snapshot of a given view. */
  - (UIView *)customSnapshoFromView:(UIView *)inputView {
  
      // Make an image from the input view.
      UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, NO, 0);
      [inputView.layer renderInContext:UIGraphicsGetCurrentContext()];
      UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
      UIGraphicsEndImageContext();
  
      // Create an image view.
      UIView *snapshot = [[UIImageView alloc] initWithImage:image];
      snapshot.layer.masksToBounds = NO;
      snapshot.layer.cornerRadius = 0.0;
      snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0);
      snapshot.layer.shadowRadius = 5.0;
      snapshot.layer.shadowOpacity = 0.4;
  
      return snapshot;
  }
  </code></pre>
  
  <p>Sadly this is crashing in the <code>UIGestureRecognizerStateChanged</code> where its trying to move cells; its to do with inconsitency of array after/before moving.</p>
  
  <p>Also, I'm not sure if I am doing it right; will this pattern work in a section based list of departments and employees?</p>
  
  <p>Regardless, my query here is: How do I add longpress gesture to a tableview cell made up of sections, or .. I would like to move Tom from Sales to Marketing using long-press.</p>
  
  <p>Given the above code, is this possible?</p>
  
  <p>Edit;</p>
  
  <p>The crash I get is:</p>
  
  <blockquote>
    <p>'NSInternalInconsistencyException', reason: 'Invalid update: invalid
    number of rows in section 0.  The number of rows contained in an
    existing section after the update (3) must be equal to the number of
    rows contained in that section before the update (3), plus or minus
    the number of rows inserted or deleted from that section (0 inserted,
    0 deleted) and plus or minus the number of rows moved into or out of
    that section (0 moved in, 1 moved out).'
    *** First throw call st</p>
  </blockquote>
  
  <hr>
  
  <p>Further update: @14-Jan-2016</p>
  
  <p>Turns out the accepted answer was still causing me crashes.  The reason was that it was assuming an exchange was occuring; when this is not the case.</p>
  
  <p>I solved the problem by repeating my code to remove an item and then re-add it back in.</p>
  
  <p>This is posted below;</p>
  
  <pre><code> case UIGestureRecognizerStateChanged: {
              CGPoint center = snapshot.center;
              center.y = location.y;
              center.x = location.x;
              snapshot.center = center;
  
              // Is destination valid and is it different from source?
              if (indexPath &amp;&amp; ![indexPath isEqual:sourceIndexPath])
              {
                  Department *departmentFrom = [_objects objectAtIndex:sourceIndexPath.section];
                  Department *departmentTo = [_objects objectAtIndex:indexPath.section];
  
                  [self.tableView beginUpdates];
  
                  Employee *employee = [departmentFrom.employees objectAtIndex:sourceIndexPath.row];
                  [departmentFrom.employees removeObjectAtIndex:sourceIndexPath.row];
                  [departmentTo.employees insertObject:employee atIndex:indexPath.row];
  
                  [self.tableView moveRowAtIndexPath:sourceIndexPath toIndexPath:indexPath];
  
                  [self.tableView endUpdates];
  
                  // ... and update source so it is in sync with UI changes.
                  sourceIndexPath = indexPath;
              }
              break;
          }
  </code></pre>
  
  <p>The only issue I can see is that both tableView:moveRowAtIndexPath and this code is repeating the same code.</p>
  
  <p>But I can clean that up later.</p>
  
  <p>Thanks</p>