iosiphonecore-datansmanagedobjectcontextmagicalrecord

MagicalRecord saveWithBlock vs saveToPersistentStoreAndWait


I am trying very hard to understand everything about MagicalRecord and CoreData. So let's say, I have 2 pieces of code doing same thing, where tallyM is a managed object running in MR_defaultContext.

Option 1:

Tally *tallyM                       = (Tally *)[Tally MR_findFirstWithPredicate:predicateM];

[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

    Tally *tallyMLocal              = [tallyM MR_inContext:localContext];
    tallyMLocal.tl_countMale        = [NSString stringWithFormat:@"%ld", (long)uiTallyMaleCounter];

} completion:^(BOOL success, NSError *error) {

        [self updateTallies_APICall:[tallyM MR_inContext:[NSManagedObjectContext MR_defaultContext]]];
}];

Option 2:

Tally *tallyM                       = (Tally *)[Tally MR_findFirstWithPredicate:predicateM];
tallyM.tl_countMale                 = [NSString stringWithFormat:@"%ld", (long)uiTallyMaleCounter];
[tallyM.managedObjectContext MR_saveToPersistentStoreAndWait];
[self updateTallies_APICall:[tallyM MR_inContext:[NSManagedObjectContext MR_defaultContext]]];

Questions:

  1. Which one is better? I understand that saveWithBlock can be used when you need async save, but is there any other difference? Is Option 1 safer or better in any way than Option 2?

  2. In Option 1, I have tallyM which runs in MR_defaultContext. Then inside saveWithBlock, I change tallyM, by changing tallyMLocal, and saving contexts. Can I be 100% sure that after saveWithBlock runs, in completion handler (when I need to continue working with tallyM), tallyM (which is still running in MR_defaultContext) will have the tl_countMale updated?

  3. In Option 1, in completion handler, do I still need to call below code? I assume (already checked with console, but just want to be sure) that tallyM still runs in MR_defaultContext, after saveWithBlock is executed. So is it needed to call again MR_inContext?

    [tallyM MR_inContext:[NSManagedObjectContext MR_defaultContext]]

  4. Let's say I don't need async save at all. So I can use Option 2, or saveWithBlockAndWait. Is saveWithBlockAndWait in any way better than Option 2?

I just want to make sure I finally correctly understood how MagicalRecords and CoreData behaves.


Solution

  • Personally, I would avoid the pattern in Option 2 there. The idea being that you should use a single Managed Object Context as the scope for operations on a collection of Managed Objects. That is why most examples use the following pattern:

    NSManagedObjectContext *localContext = //...;
    NSManagedObject *localObject = [otherObject MR_inContext:localContext];
    ///make changes to localObject
    [localContext MR_saveToPersistentStoreAndWait];
    

    The [MagicalRecord saveWithBlock:] method basically implements this pattern in a more convenient API.

    I would also recommend not using the defaultContext implicitly. Be more explicit about that in your code because you may need to swap that out when your app starts to deal with threads.

    The completion handlers are written in a way that they are always called back after the save operation is 100% complete. I recommend reading the source code to see for yourself.