Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot reorder an NSOrderedSet relationship in Core Data

Does anyone know why I cannot save a change in the order of objects in an NSOrderedSet relationship in Core Data? I already know of the bug where using the generated functions for an NSOrderedSet relationship does not work well, and so I always use the keypath. Below is the code for two functions in a tableview.

The tableView:moveRowAtIndexPath:toIndexPath: claims to save successfully, but the change is actually not saved, meaning if I perform a [tableView reloadData];, the old order is still there. Even if I exit the app and restart it, the order has not changed. I have verfified this with multiple NSLogs. The second function, tableView:commitEditingStyle:forRowAtIndexPath:, which I use to delete an NSOrderedSet entry, works perfectly.

My theory is that Core Data discards the order information from the NSOrderedSet relationship in its internal representation, and so because the objects remain the same, it figures it doesn't need to save anything. Has anyone experienced anything like this before? If so, did you find a work-around?

-(void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath 
{

    NSManagedObjectContext *context= [self managedObjectContext];

    Playlist *playlist = (Playlist*) [context objectWithID:playlistID];


    [playlist willChangeValueForKey:@"tracks"];
    NSMutableOrderedSet *exchange = [playlist mutableOrderedSetValueForKey:@"tracks"];;

    NSInteger fromIndex = sourceIndexPath.row;
    NSInteger toIndex = destinationIndexPath.row;

    NSMutableArray *arrayOfTracks = [NSMutableArray arrayWithArray:[exchange array]];

    [arrayOfTracks exchangeObjectAtIndex:fromIndex withObjectAtIndex:toIndex];
    [[playlist mutableOrderedSetValueForKey:@"tracks"] removeAllObjects];


    [[playlist mutableOrderedSetValueForKey:@"tracks"] addObjectsFromArray:arrayOfTracks];
    playlist.md5Hash = nil;
    [playlist didChangeValueForKey:@"tracks"];

    NSError *savingError = nil;
    if ([context save:&savingError]){
        NSLog(@"Successfully saved the context for reorder"); 
    } else {
        NSLog(@"Failed to save the context. Error = %@", savingError); }

}


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSManagedObjectContext *context= [self managedObjectContext];

        Playlist *playlist = (Playlist*) [context objectWithID:playlistID];

        Track *track = [self.tracksFRC objectAtIndexPath:indexPath];    


        NSMutableOrderedSet *exchange = [NSMutableOrderedSet orderedSetWithOrderedSet: playlist.tracks];


        [exchange removeObject:track];
        [track removeBelongingPlaylistObject:playlist];
        NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [playlist.tracks count])];

        [[playlist mutableOrderedSetValueForKey:@"tracks"] replaceObjectsAtIndexes:indexSet withObjects:[exchange array]];

        playlist.md5Hash = nil;

        NSError *savingError = nil;
        if ([context save:&savingError]){
            NSLog(@"Successfully saved the context for remove entry"); 
        } else {
            NSLog(@"Failed to save the context. Error = %@", savingError); }
    }
}

EDIT: I was able to solve the problem by calling [context save:&savingError] twice, once with the records removed, and once with them reinserted in the new order. This fix shouldn't really be necessary though.

like image 867
deleterOfWorlds Avatar asked Feb 28 '12 16:02

deleterOfWorlds


1 Answers

Converting @ikuramedia's code to swift gives:

var exchange: NSMutableOrderedSet = playlist.tracks.mutableCopy() as! NSMutableOrderedSet

exchange.exchangeObjectAtIndex(fromIndexPath.row, withObjectAtIndex: toIndexPath.row)

playlist.tracks = exchange

In case anyone needs it

like image 152
Derek Avatar answered Oct 21 '22 17:10

Derek