Question

I'm trying to best format my project's use of RestKit and Core Data. There are a couple of things that I've got working, but I have a feeling they are implemented poorly and potentially thread unsafe... I have an object that manages all of my data transfer, storage, etc., which has a function that sets up restkit. I have an instance variable that I use for RKObjectManager, and in this setup function I create the objectStore, setup all the attribute mappings, create the persistent store, etc., - all of the normal restkit setup code. Outside of this function, the only thing available to this object is the _objectManager instance variable, which I've been using for NSFetchRequests and such.

There are two things I want to make sure I'm implementing properly, fetching managed objects, and savings changes to managed objects.

If I want to update a property on an object, I've been doing this:

object.whatever = @"something here";

NSError *error;
if (![object.managedObjectContext save:&error]) {
    // log the error here
}

Is this the proper way to update/save a property on an object? Is accessing the object's managed object context directly save to do at any point in the code, or is this something that should be done only in the background/foreground? My current implementation could potentially have this called in both the background and foreground and I just want to make sure this is acceptable.

When I want to fetch an object, I wrote a function that takes an entity name, an array of predicates, and a sort descriptor as parameters so it can be reused:

    NSManagedObjectContext *managedObjectContext = // I DONT KNOW WHAT TO PUT HERE! //

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

    NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
    [fetchRequest setPredicate:compoundPredicate];

    NSError *error;
    NSArray *fetchedRecords = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

    if (error) {
        // log error
    }

    // if we were given a sort descriptor, sort the array appropriately
    if (sortDescriptor) {
        fetchedRecords = [fetchedRecords sortedArrayUsingDescriptors:@[sortDescriptor]];
    }

    return fetchedRecords;

My problem here is creating/accessing the correct managed object context. How should I do this? Do I access some property on the RKObjectManager I created before such as:

_objectManager.managedObjectStore.mainQueueManagedObjectContext

or is that not thread safe because its for the main thread? What can I do to make sure I'm using the right managed object context, and that it is thread safe? I was using:

_objectManager.managedObjectStore.persistentStoreManagedObjectContext

but I was told this was definitely not best practice and was not thread safe, so I'm trying to determine the best solution.

EDIT - perhaps I can call this function to get the context whenever I want to fetch objects?

- (NSManagedObjectContext *)getManagedObjectContext {
    if ([NSThread isMainThread]) {
        return _objectManager.managedObjectStore.mainQueueManagedObjectContext;
    }
    else {
        return [_objectManager.managedObjectStore newChildManagedObjectContextWithConcurrencyType:NSPrivateQueueConcurrencyType tracksChanges:YES];
    }
}
Was it helpful?

Solution

For saving, instead of this:

if (![object.managedObjectContext save:&error]) {

you should do:

if (![object.managedObjectContext saveToPersistentStore:&error]) {

so that the changes are persisted right up the chain to the on-disk store. You should only be doing this on the thread that created / fetched the managed object (thus the thread ownership of the MOC is maintained).

Foreground / background isn't important so much as which MOC is used by each thread. If the MOC thread ownership is respected then you should be fine.

Same applies to fetching. For UI updates, you must use the main thread and the mainQueueManagedObjectContext. You should never directly use the persistentStoreManagedObjectContext. For arbitrary background threads you should be asking the managed object store to create a new child managed object context for you and using that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top