Open sarn opened 9 years ago
Hey,
Thanks for report. Do you use beginUpdates
and endUpdates
method of the RATreeView
when you perform batched updates?
Yes I do.
@sarn Can you verify whether NSFetchedResultsController
doesn't work correctly with version 1.0.3
?
Note: RATreeView
was written in a way that it should work correctly with NSFetchedResultsController
. If this is still not the case, I will try to investigate the issue (despite the fact it can take some time as I am pretty busy now).
@Augustyniak Thanks for the update, I verified with 1.0.3
and still see the same thing. My test uses only a few items without any childs to make things simple. Simple inserts
and deletes
work fine as long as items I add or remove are at the end of the list and no NSFetchedResultsChangeMove
is involved for reordering items.
Things don't work as expected if any reordering happens, even simple reorderings, like "move one item one row up". The tree is not or only partially updated and does not seem to move all items correctly. Depending on the test case, some items got moved while others are not.
My NSFetchedResultsChangeMove
handling is pretty simple and looks like this:
[self.treeView deleteItemsAtIndexes:[NSIndexSet indexSetWithIndex:indexPath.row] inParent:nil withAnimation:RATreeViewRowAnimationNone];
[self.treeView insertItemsAtIndexes:[NSIndexSet indexSetWithIndex:newIndexPath.row] inParent:nil withAnimation:RATreeViewRowAnimationNone];
I am seeing pretty good results while using core data, my handling is pretty simple as I'm only working with a single leaf tree. The only issue I'm currently working through is handling insertions and deletions to children nodes. When you add a child to a root object the change method is invoked with the parent object and an update action. Both index paths are identical as well so I'm struggling to come up with a way to figure out what type of operation happened under the parent.
[_treeView reloadRowsForItems:@[anObject] withRowAnimation:RATreeViewRowAnimationAutomatic];
does not refresh the parent objects children. The only way I can seem to get the parent to reload its children is to manually open and close the tree.
- (void) controllerWillChangeContent:(NSFetchedResultsController *)controller {
[_treeView beginUpdates];
}
- (void) controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
switch (type){
case NSFetchedResultsChangeInsert:
[_treeView insertItemAtIndex:newIndexPath.row
inParent:nil
withAnimation:RATreeViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeDelete:
[_treeView deleteItemsAtIndexes:[NSIndexSet indexSetWithIndex:(NSUInteger) newIndexPath.row]
inParent:nil
withAnimation:RATreeViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeMove:
[_treeView moveItemAtIndex:indexPath.row
inParent:nil
toIndex:newIndexPath.row
inParent:nil];
break;
case NSFetchedResultsChangeUpdate: {
[_treeView reloadRowsForItems:@[anObject] withRowAnimation:RATreeViewRowAnimationAutomatic];
break;
}
}
}
- (void) controllerDidChangeContent:(NSFetchedResultsController *)controller {
[_treeView endUpdates];
}
The
NSFetchedResultsControllerDelegate
methoddidChangeObject
informs about changes to the data source, like inserts, deletes, updates and moves that occurred in a CoreData object store.A standard
UITableView
can react to those changes by providing methods which one can use to inform theUITableView
. A simple way to implement this would look likeRATreeView
seems to lack 100% compatibility. I found the following two methods that support inserts and deletes quite well:But it does not work for the
NSFetchedResultsChangeMove
type. An implementation similar to theUITableView
by chaining delete and insert right after each other leads to inconsistencies or crashes.I also tried the following
RATreeView
methodbut unfortunately this moves a cell to the newIndex and right back to the original index, because the
NSFetchedResultsChangeMove
gets triggered multiple times in a run. We get informed about all moves of all cells. First you get informed that the cell should get moved to the newIndex, then you get informed that the previous cell, that was occupying newIndex, should get moved away from that. BasicallymoveItemAtIndex:
seems not to be designed for this use case.Do I miss something? Is there any other way to get
RATreeView
working withNSFetchedResultsControllerDelegate
?I would be happy to contribute to
RATreeView
to make this possible, if needed. But I lack knowledge of the inner design ofRATreeView
and would need some insight of the original developer.