Should NSFetchRequest be explicitly performed on context queue?

35 views Asked by At

Just a little question...

When performing CoreData requests (in objective-C), do I have to make them on the context queue explicitly, or are they assumed to do that by themselves?

In other words can I just write:

NSArray *results = [context executeFetchRequest:request error:nil];

Or do I have to write (if I want to avoid issues):

__block NSArray *results = nil;
[context performBlockAndWait:^{
    results = [context executeFetchRequest:request error:nil];
}];

Thanks!

2

There are 2 answers

1
Tom Harrington On

You can never assume that Core Data will use the correct queue. You always need to tell it via one of the “perform” methods. The only exception is if you have a main-queue context and you know your code is running on the main queue. You can skip “perform” in that one and only case.

You mention using a convenience method to do a fetch, using “perform” inside the method. That’s fine, but don’t forget that you also need to use “perform” any time you use any of the fetched objects. For example, you can’t use property values from fetched objects unless you also use “perform” (again with the one exception I mentioned).

0
Thomas Albert On

So just to be sure Tom:

All my CoreData objects (subclasses of NSManagedObject) have their CoreData properties as private (with a prefix "cd_"). I never expose them and use wrapper properties instead:

- (nullable NSString *) email {
    return self.cd_email;
}

I've created a method on NSManagedObject:

- (id) safeValueForProperty: (SEL)property {
    __block id value = nil;
    [self.managedObjectContext performBlockAndWait:^{
        value = [self valueForKey:NSStringFromSelector(property)];
    }];
    return value;
}

So now I can use (from any thread in theory):

- (nullable NSString *) email {
    return [self safeValueForProperty:@selector(cd_email)];
}

(and of course the same for setters).

Am I doing right?