Skip to content

Instantly share code, notes, and snippets.

@bradya
Created January 28, 2015 02:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bradya/0f17bb779efd92c3f7b5 to your computer and use it in GitHub Desktop.
Save bradya/0f17bb779efd92c3f7b5 to your computer and use it in GitHub Desktop.
Core Data queue abstraction
#pragma mark - Block Methods
/*
When we team switch, we want to completely stop in-progress data changes
E.g. if we're dumping the cache on Team A and you switch teams, we use
[SLKTeam currentTeam] throughout the app, and when that code executes, it'll
do stuff for the wrong team.
Core Data doesn't provide direct access to the MOC queues, so we implement
our own queues on top of the MOC queues which gives us the ability to
pause the queues, cancel operations, and generally ensure that operations
happen when we want them to, instead of when Core Data wants them to.
*/
+ (void)performMainBlock:(void (^)())block
{
[self performContextBlock:SLKContextTypeMain block:block];
}
+ (void)performBackgroundBlock:(void (^)())block
{
[self performContextBlock:SLKContextTypeBackground block:block];
}
+ (void)performReadBlock:(void (^)())block
{
[self performContextBlock:SLKContextTypeRead block:block];
}
+ (void)performContextBlock:(SLKContextType)contextType block:(void (^)())block
{
// Give up immediately if we don't have a block
if (!block) {
return;
}
// Get the context and queue for the specified context type
// This allows us to write this logic once
NSManagedObjectContext *context = [self contextForType:contextType];
NSOperationQueue *queue = [self queueForType:contextType];
// Adds the operation to the queue
[queue addOperationWithBlock:^{
/*
We use a dispatch group to block the thread that the NSOperationQueue is
operating on, so operations are only fired off to the Core Data queues
one at a time.
This makes it so that if we pause the queue or cancel all operations,
the only block being executed in the MOC finishes, blocking the main thread
while we wait for it to complete (a necessary evil, for now)
*/
__block dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
// We want to use performBlock because it provides us with
// a free autoreleasepool and synchronizes changes better than performBlockAndWait
[context performBlock:^{
block(); // Actually execute the logic here
dispatch_group_leave(group); // Release the group, which is blocking the calling thread
}];
// Block the queue's thread until performBlock completes
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment