【前提条件】
- あらかじめ、対象のManagedObjectに「position」というプロパティを作っておきます。
- UITableViewの中身はNSFetchedResultsControllerで管理しておきます。
- NSFetchedResultsControllerに渡すFetchRequestに、「position」でソートするようSortDescriptorを設定しておきます。
// Edit the sort key as appropriate. NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"position" ascending:YES]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
セルが移動された際、以下のようなコードでpositionの値を書き換えることで、入れ替えが実現できました。
クラス名は、対象にするモデルクラスに書き換えてください。
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSManagedObjectContext *context = [[MRAppDelegate sharedDelegate] managedObjectContext];
MyObject* targetObject = (MyObject *)[self.fetchedResultsController objectAtIndexPath:fromIndexPath];
MyObject* previousObject = nil;
MyObject* nextObject = nil;
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:fromIndexPath.section];
if (fromIndexPath.row < toIndexPath.row) {
previousObject = (MyObject *)[self.fetchedResultsController objectAtIndexPath:toIndexPath];
if ([sectionInfo numberOfObjects] - 1 != toIndexPath.row) {
nextObject = (MyObject *)[self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:toIndexPath.row + 1 inSection:toIndexPath.section]];
}
} else {
if (toIndexPath.row != 0) {
previousObject = (MyObject *)[self.fetchedResultsController objectAtIndexPath:[NSIndexPath indexPathForRow:toIndexPath.row - 1 inSection:toIndexPath.section]];
}
nextObject = (MyObject *)[self.fetchedResultsController objectAtIndexPath:toIndexPath];
}
float sakura = 1;
float aya = 0;
if (nextObject) {
if (previousObject) {
sakura = (nextObject.position - previousObject.position) / 2;
} else {
aya = nextObject.position - sakura * 2;
}
}
if (previousObject) {
aya = previousObject.position;
}
targetObject.position = sakura + aya;
[context save:nil];
}
ただ、これだけだとTableViewに更新が行き渡らないので、
以下のように、controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:
にてフックして、reloadDataをするとうまくいきます。
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;
switch(type)
{
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView reloadData];
break;
}
}
「position」というプロパティを作らず、ArrangedなRelationshipを定義して、それを使ってソートする方法もありますが、
iOS 4が対応していないため今回は使っていません。