Search code examples
iosobjective-cmagicalrecord

Magical Record IOS objective C. What context should we create?


Hi I'm working with Core Data IOS using magical record library for objective C. The library have many NSManageObjectContext initiation. What should we use in order to keep app perfomance and good user experience?

there are many

+ [NSManagedObjectContext MR_newContext]: Sets the default context as it's parent context. Has a concurrency type of NSPrivateQueueConcurrencyType.
+ [NSManagedObjectContext MR_newMainQueueContext]: Has a concurrency type of NSMainQueueConcurrencyType.
+ [NSManagedObjectContext MR_newPrivateQueueContext]: Has a concurrency type of NSPrivateQueueConcurrencyType.
+ [NSManagedObjectContext MR_newContextWithParent:…]: Allows you to specify the parent context that will be set. Has a concurrency type of NSPrivateQueueConcurrencyType.
+ [NSManagedObjectContext MR_newContextWithStoreCoordinator:…]: Allows you to specify the persistent store coordinator for the new context. Has a concurrency type of NSPrivateQueueConcurrencyType.

What context initiation is good one?

For example this function deal with JSON response and save record to database whenever successfully receive the resonse

NSManagedObjectContext *localContext = [NSManagedObjectContext MR_context];


        [Stamp MR_truncateAllInContext:localContext];

                [responseJSON[@"root"] enumerateObjectsUsingBlock:^(id attributes, NSUInteger idx, BOOL *stop) {
                    Stamp *stamp = [Stamp MR_createEntityInContext:localContext];
                    [stamp setOrderingValue:idx];
                [stamp updateWithApiRepresentation:attributes];
        }];

        [localContext MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
            if (completionBlock) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    completionBlock(!error, error);
                });
            }
        }];

And this function perform fetch request

+ (NSArray *)yearsDropDownValues
{
    NSManagedObjectContext *moc = [NSManagedObjectContext MR_rootSavingContext];

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [Stamp entityInManagedObjectContext:moc];
    request.entity = entity;
    request.propertiesToFetch = @[StampAttributes.year];
    request.returnsDistinctResults = YES;
    request.resultType = NSDictionaryResultType;
    request.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:StampAttributes.year ascending:NO]];

    NSArray *years = [moc executeFetchRequest:request error:nil];

    NSMutableArray *res = [NSMutableArray array];
    for (NSDictionary *year in years) {
        [res addObject:@{@"code": [NSString stringWithFormat:@"%@ Collections", year[@"year"]], @"value": year[@"year"] }];
    }

    return res;
}

Any help is much appreciate. Thanks


Solution

  • Before I start, I think there are two more contexts you should know and understand, they are created automatically when you use MagicalRecord's default way to setup your CoreData stack:

    1. MR_rootSavingContext, it is a private queue context directly connect to the coordinator, usually it will be your root context.
    2. MR_defaultContext, it is a main queue context, which has MR_rootSavingContext as its parent, usually it will be your UI context, use it to fetch and show your data on the screen.

    Now I will explain those five context one by one:

    1. MR_newContext, a new private queue context which has MR_defaultContext as its parent context. It is equivalent of calling [NSManagedObjectContext MR_newContextWithParent:[NSManagedObjectContext ME_defaultContext]]. This type of context is good for heavy batch operations, like inserting, updating, deleting 100s of objects. Since all the operations are running on the background thread, the UI will not be blocked. However the drawbacks are, it brings extra complexity, especially when you have more than one of such context, conflicts will probably occur when save these contexts.
    2. MR_newMainQueueContext, a new main queue context which does not have parent context. It is the sibling of MR_rootSavingContext, as they are connecting to the same NSPersistentStoreCoordinator. All the operations you do on this type of context will block the UI, so do not do any heavy work on this context.
    3. MR_newPrivateQueueContext, similar to MR_newContext, but it does not have parent context. It is the sibling of MR_rootSavingContext.
    4. MR_newContextWithParent, a convenient way to create a private queue context as well as specify the parent context.
    5. MR_newContextWithStoreCoordinator, a new private queue context which is using a specified NSPersistentStoreCoordinator. From my point of view, only if you know how to use contexts with different coordinator properly, do not use it.

    So in a word, there is no good or bad among these contexts, you need to choose the right one based on your requirement.