Rearranging UITableView with Core Data
Here's what's officially working now, with deletes, moves, and inserts. I "validate" the order any time there's an edit action affecting the order.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section != kHeaderSection) {
if (editingStyle == UITableViewCellEditingStyleDelete) {
@try {
LinkObj * link = [self.fetchedResultsController objectAtIndexPath:indexPath];
debug_NSLog(@"Deleting at indexPath %@", [indexPath description]);
//debug_NSLog(@"Deleting object %@", [link description]);
if ([self numberOfBodyLinks] > 1)
[self.managedObjectContext deleteObject:link];
}
@catch (NSException * e) {
debug_NSLog(@"Failure in commitEditingStyle, name=%@ reason=%@", e.name, e.reason);
}
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// we need this for when they click the "+" icon; just select the row
[theTableView.delegate tableView:tableView didSelectRowAtIndexPath:indexPath];
}
}
}
- (BOOL)validateLinkOrders {
NSUInteger index = 0;
@try {
NSArray * fetchedObjects = [self.fetchedResultsController fetchedObjects];
if (fetchedObjects == nil)
return NO;
LinkObj * link = nil;
for (link in fetchedObjects) {
if (link.section.intValue == kBodySection) {
if (link.order.intValue != index) {
debug_NSLog(@"Info: Order out of sync, order=%@ expected=%d", link.order, index);
link.order = [NSNumber numberWithInt:index];
}
index++;
}
}
}
@catch (NSException * e) {
debug_NSLog(@"Failure in validateLinkOrders, name=%@ reason=%@", e.name, e.reason);
}
return (index > 0 ? YES : NO);
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
NSArray * fetchedObjects = [self.fetchedResultsController fetchedObjects];
if (fetchedObjects == nil)
return;
NSUInteger fromRow = fromIndexPath.row + NUM_HEADER_SECTION_ROWS;
NSUInteger toRow = toIndexPath.row + NUM_HEADER_SECTION_ROWS;
NSInteger start = fromRow;
NSInteger end = toRow;
NSInteger i = 0;
LinkObj *link = nil;
if (toRow < start)
start = toRow;
if (fromRow > end)
end = fromRow;
@try {
for (i = start; i <= end; i++) {
link = [fetchedObjects objectAtIndex:i]; //
//debug_NSLog(@"Before: %@", link);
if (i == fromRow) // it's our initial cell, just set it to our final destination
link.order = [NSNumber numberWithInt:(toRow-NUM_HEADER_SECTION_ROWS)];
else if (fromRow < toRow)
link.order = [NSNumber numberWithInt:(i-1-NUM_HEADER_SECTION_ROWS)]; // it moved forward, shift back
else // if (fromIndexPath.row > toIndexPath.row)
link.order = [NSNumber numberWithInt:(i+1-NUM_HEADER_SECTION_ROWS)]; // it moved backward, shift forward
//debug_NSLog(@"After: %@", link);
}
}
@catch (NSException * e) {
debug_NSLog(@"Failure in moveRowAtIndexPath, name=%@ reason=%@", e.name, e.reason);
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
@try {
switch (type) {
case NSFetchedResultsChangeInsert:
[theTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self validateLinkOrders];
break;
case NSFetchedResultsChangeUpdate:
break;
case NSFetchedResultsChangeMove:
self.moving = YES;
[self validateLinkOrders];
break;
case NSFetchedResultsChangeDelete:
[theTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self validateLinkOrders];
break;
default:
break;
}
}
@catch (NSException * e) {
debug_NSLog(@"Failure in didChangeObject, name=%@ reason=%@", e.name, e.reason);
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.theTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.theTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// The fetch controller has sent all current change notifications, so tell the table view to process all updates.
@try {
if (self.theTableView != nil) {
//[self.theTableView endUpdates];
if (self.moving) {
self.moving = NO;
[self.theTableView reloadData];
//[self performSelector:@selector(reloadData) withObject:nil afterDelay:0.02];
}
[self performSelector:@selector(save) withObject:nil afterDelay:0.02];
}
}
@catch (NSException * e) {
debug_NSLog(@"Failure in controllerDidChangeContent, name=%@ reason=%@", e.name, e.reason);
}
}
How to save tableView order after reordering cells in swift 4
You'll need to have some sort of property (attribute) in your core data model so that you can save the order number into the database. That way, when you fetch, you can use a sort descriptor to sort on the order number.
Related Topics
How to Make a Function Operate on a Sequence of Optional Values
Passing Values Between Viewcontrollers Based on List Selection in Swift
Continuous Rotation of Nsimageview (So It Appears to Be Animated)
Add [Unowned Self] to The Closure Argument Swift
How to Force Sktextureatlas Created from a Dictionary to Not Modify Textures Size
How to Navigate from Initial UIviewcontroller to UIsplitviewcontroller in Swift
Changing a Label in Prepareforsegue
Open View Controller When Remote Notification Pressed
Access Each Header and Controls in The Tableview in Swift
Swiftui New App Lifecycle How to Connect The Facebook Sdk
Swift Struct Adopting Protocol with Static Read-Write Property Doesn't Conform
Core Data Appears to Lose Data After Xcode Upgrade
Sdwebimage, Swift: Sdwebimagerefreshcached Unresolved Identifier
How to Prevent SQL Injections with User-Search-Terms in Vapor 4 (Fluent 4)