Augustyniak / RATreeView

Library providing easy-to-use interface for displaying tree structures on iOS and tvOS.
MIT License
2.49k stars 465 forks source link

NSInternalInconsistencyException on method reloadRowsForItems:withRowAnimation: for child item of collapsed parent #184

Open serhiikrivtsov opened 8 years ago

serhiikrivtsov commented 8 years ago

In the current implementation of method reloadRowsForItems:withRowAnimation:

- (void)reloadRowsForItems:(NSArray *)items withRowAnimation:(RATreeViewRowAnimation)animation
{
   NSMutableArray *indexes = [NSMutableArray array];
   UITableViewRowAnimation tableViewRowAnimation = [RATreeView tableViewRowAnimationForTreeViewRowAnimation:animation];
   for (id item in items) {
     NSIndexPath *indexPath = [self indexPathForItem:item];
    [indexes addObject:indexPath];
  }

  [self.tableView reloadRowsAtIndexPaths:indexes withRowAnimation:tableViewRowAnimation];
}

When we call it for child item of collapsed parent in the line NSIndexPath *indexPath = [self indexPathForItem:item] we receive incorrect indexPath. As result, in the cases when this incorrect indexPath is out of range for tableView (it happens when index of row for child to reload, when it's parent expanded, bigger then number of rows in tableView, when it's parent collapsed) , we get such exception:

* Assertion failure in -[RATableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UITableView.m:1422 * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 12 from section 0 which only contains 11 rows before the update'

To avoid this situation, before reloading such children (children which parents could be collapsed on moment of reloading) i check if cells for this items are visible, using this method of treeView cellForItem: which returns nil if cell for given item is not visible. And the question is: Do i need to do this check or you should implement this internally?

zhouhao27 commented 7 years ago

Got the same problem. But how do you check if the child is visible or not? My code:

    if let visible = treeView.itemsForVisibleRows  {
      if visible.filter({ el in el == item.value }).count > 0 {
        treeView.reloadRows(forItems: [item.value], with: RATreeViewRowAnimationFade)
      }
    }