Oleksandr Matrosov
Oleksandr Matrosov

Reputation: 27159

MagicalRecord saveInBackgroundWithBlock does not save object

This code works wonderful for me and Option is saved even when I rerun application.

 Player *selectedPlayer = [_players objectAtIndex:indexPath.row];

    [MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {

        Option *option = [Option MR_createInContext:localContext];

        option.playerID = selectedPlayer.playerID;

        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"playerID == %@", selectedPlayer.playerID];

        Player *foundPlayer = [Player MR_findFirstWithPredicate:predicate inContext:localContext];

        [foundPlayer addOptionObject:option];

        [[STGameHelper sharedInstance].selectedGame addPlayersObject:selectedPlayer];

    } completion:^{

        if ([self.delegate respondsToSelector:@selector(didSelectedPlayer)])
        {
            [self.delegate didSelectedPlayer];
        }

    }];

But if try this the data base does not have any Option objects after rerun application.

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {

    Option *option = [Option MR_createInContext:localContext];

    option.playerID = selectedPlayer.playerID;

    Player *selectedPlayer = [_players objectAtIndex:indexPath.row];

    [selectedPlayer addOptionObject:option];

    [[STGameHelper sharedInstance].selectedGame addPlayersObject:selectedPlayer];

} completion:^{

    if ([self.delegate respondsToSelector:@selector(didSelectedPlayer)])
    {
        [self.delegate didSelectedPlayer];
    }

}];

I suppose that I work in different context, but I don't understand how it works under the hood. So the Player entries are stored in database without any issues. Why I can't choose already saved Player record and attach for this entity new record that has beed created in some context.

I suppose some context is distorted when I rerun app and the data base deletes Options entities using internal rules which selected for concert attribute (cascade etc). Am I right or maybe I confused?

Upvotes: 0

Views: 361

Answers (1)

Dan Shelly
Dan Shelly

Reputation: 6011

I really know nothing of MagicalRecord but ... You do seem to have a cross context issue here ...

When using CoreData, a managed object is tightly bound to its managed context.
You cannot link objects from 2 different contexts.

In your second code segment you take an object inserted in localContext (which i believe is a temporary private queue context), your option, and link it to an existing object from another context (probably your main context).

You need to import the selectedPlayer to your local context by:

NSManagedObjectID* selectedPlayerID = [[_players objectAtIndex:indexPath.row] objectID];
NSError* error = nil;
Player* selectedPlayer = [localContext existingObjectWithID:selectedPlayerID error:&error];
//handle error if needed ...

This will prevent your cross context issues.

Another thing:

Your code is executed in the background, so by the time it is executed [_players objectAtIndex:... might change.

You better obtain the player object id prior to declaring the block and trap that object ID in the block:

NSManagedObjectID* selectedPlayerID = [[_players objectAtIndex:indexPath.row] objectID;
[MagicalRecord saveInBackgroundWithBlock:^{/*your code here using selectedPlayerID*/}];

Upvotes: 2

Related Questions