Skip to content

Instantly share code, notes, and snippets.

@puppybits
Last active December 17, 2015 16:29
Show Gist options
  • Save puppybits/5638851 to your computer and use it in GitHub Desktop.
Save puppybits/5638851 to your computer and use it in GitHub Desktop.
Core Data FreezeDry. Add Multithreading API to the NSManagedObject to share/pass between threads, with either sync or async GCD dispatch queues.
//
// CoreData+FreezeDry.h
// Streamlines transfering a single core data entity between treads.
// This WILL run SLOW with lots of data.
// Minimize changing threads!
// Use it on single objects.
// Use it as an example to batch transfer a large set of data.
//
// Created by Bobby Schultz on 1/13/12.
//
// @example:
// __block NSManagedObjectID *frozenID = myModel.slowFreezeDry;
//
// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//
// NSManagedObjectContext *backgroundContext = [NSManagedObjectContext initContextForCurrentThread];
// MyObject *myBackgroundModel = (MyObject*)[frozenID slowRehydrateWithContext:backgroundContext];
//
// [myBackgroundModel updateFromSlowWebService];
//
// frozenID = myBackgroundModel.slowFreezeDry;
// dispatch_async(dispatch_get_main_queue(), ^{
// MyObject *myMainModel = (MyObject*)[frozenID slowRehydrateWithContext:appDelegate.moc];
// [self refreshView];
// });
// }
//
// [threadContext release];
// });
//
#import <CoreData/CoreData.h>
@interface NSManagedObjectID (FreezeDry)
- (NSManagedObject*) slowRehydrateWithContext:(NSManagedObjectContext*)context;
@end
@interface NSManagedObject (FreezeDry)
- (NSManagedObjectID*) slowFreezeDry;
@end
@interface NSManagedObjectContext (FreezeDry)
+ (NSManagedObjectContext*) initContextForCurrentThread;
@end
//
// CoreData+FreezeDry.m
//
// Created by Bobby Schultz on 1/13/12.
//
#import "CoreData+FreezeDry.h"
@implementation NSManagedObjectID (FreezeDry)
- (NSManagedObject*) slowRehydrateWithContext:(NSManagedObjectContext*)context
{
// Reload the frozen object
NSManagedObject* obj;
obj = [context objectWithID:self];
// Make sure it doesn't have brain damage
if (obj == nil || obj.entity == nil) return nil;
// Make sure its fully thawed
if ([obj isFault])
{
NSError *error = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF = %@", obj];
NSFetchRequest *fetcher = [NSFetchRequest fetchRequestWithEntityName:obj.entity.name];
[fetcher setPredicate:predicate];
// Load it into the managed context for this thread
NSArray *results = [context executeFetchRequest:fetcher error:&error];
// Make sure it's really there
if(results == nil || results.count == 0)
return nil;
// Set object so it can be returned to the land of the living
obj = [results objectAtIndex:0];
}
// Done and done
return obj;
}
@end
@implementation NSManagedObject (FreezeDry)
- (NSManagedObjectID*) slowFreezeDry
{
// Make sure it's shareable across threads
BOOL isMain = (dispatch_get_current_queue() == dispatch_get_main_queue() ? YES : NO);
// Block the current thread until data is written. This is SLOOOOW
if (isMain) {
NSError *error = nil;
[self.managedObjectContext save:&error];
} else {
dispatch_sync(dispatch_get_current_queue(), ^{
dispatch_sync(dispatch_get_main_queue(), ^{
NSError *error = nil;
[self.managedObjectContext save:&error];
});
});
}
// NSManagedObjectIDs are threadsafe
return self.objectID;
}
@end
@implementation NSManagedObjectContext (FreezeDry)
+ (NSManagedObjectContext*) initContextForCurrentThread
{
NSPersistentStoreCoordinator* coordinator;
NSManagedObjectContext* moc;
NSObject<UIApplicationDelegate>* delegate;
// Create new MOC for current thread
moc = [[NSManagedObjectContext alloc] init];
delegate = [[UIApplication sharedApplication] delegate];
if (![delegate respondsToSelector:@selector(persistentStoreCoordinator)])
return nil;
// Set the default store
coordinator = [delegate performSelector:@selector(persistentStoreCoordinator)];
moc.persistentStoreCoordinator = coordinator;
return moc;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment