Skip to content

Instantly share code, notes, and snippets.

@patcoll
Created April 15, 2011 20:55

Revisions

  1. patcoll created this gist Apr 15, 2011.
    10 changes: 10 additions & 0 deletions AppDelegate.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    #define SYNC_INTERVAL 60

    @interface AppDelegate : NSObject <UIApplicationDelegate> {
    // ...
    NSMutableDictionary *mocs;
    NSMutableDictionary *mocThreads;
    // ...
    }
    @property (nonatomic, retain) NSMutableDictionary *mocs;
    @property (nonatomic, retain) NSMutableDictionary *mocThreads;
    132 changes: 132 additions & 0 deletions AppDelegate.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,132 @@
    // put this somewhere in @implementation:
    // @synthesize mocs, mocThreads;

    - (void)awakeFromNib {
    [NSTimer scheduledTimerWithTimeInterval:SYNC_INTERVAL target:self selector:@selector(sync) userInfo:nil repeats:YES];

    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(threadWillExit:)
    name:NSThreadWillExitNotification
    object:nil];
    }

    - (void) sync
    {
    [self performSelectorInBackground:@selector(doSync) withObject:nil];
    }

    - (void) doSync
    {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    NSManagedObjectContext *ctx = [self managedObjectContext];
    // sync! ctx will be a fresh MOC within a new thread

    [pool release];
    }


    - (void) threadWillExit:(NSNotification *)notification
    {
    NSThread *exitingThread = [notification object];
    [self destroyManagedObjectContextForThreadName:[exitingThread name]];
    }


    - (void) mergeChanges:(NSNotification *)notification
    {
    // Merge changes from the MOC that sent the notification to all other MOCs in all other threads.
    NSManagedObjectContext *mocThatSentNotification = [notification object];

    [mocs enumerateKeysAndObjectsUsingBlock:^(id name, id moc, BOOL *stop) {
    name = (NSString *)name;
    moc = (NSManagedObjectContext *)moc;
    NSThread *thread = [mocThreads objectForKey:name];

    // don't send notifications back to the MOC that sent it.
    if (![moc isEqual:mocThatSentNotification]) {
    // waitUntilDone:NO because the thread could exit prematurely -- and we don't really care why.
    [moc performSelector:@selector(mergeChangesFromContextDidSaveNotification:) onThread:thread withObject:notification waitUntilDone:NO];
    }
    }];
    }


    // ...

    /**
    Returns the managed object context for the current thread.
    If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
    */
    - (NSManagedObjectContext *)managedObjectContext
    {
    if (mocs == nil) {
    self.mocs = [[NSMutableDictionary alloc] init];
    }

    if (mocThreads == nil) {
    self.mocThreads = [[NSMutableDictionary alloc] init];
    }

    static int counter = 0;
    NSThread *current = [NSThread currentThread];

    if ([current name] != nil && [mocs objectForKey:[current name]] != nil) {
    return [mocs objectForKey:[current name]];
    }

    [current setName:[NSString stringWithFormat:@"%d", ++counter]];

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil) {
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
    [moc setPersistentStoreCoordinator:coordinator];

    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(mergeChanges:)
    name:NSManagedObjectContextDidSaveNotification
    object:moc];
    [mocs setObject:moc forKey:[current name]];
    [mocThreads setObject:current forKey:[current name]];
    }

    return [mocs objectForKey:[current name]];
    }

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // return a valid NSPersistentStoreCoordinator
    }

    - (NSString *) mainThreadName
    {
    NSSet *mainThreadNameSet = [mocThreads keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL *stop) {
    return [obj isEqual:[NSThread mainThread]];
    }];
    return [mainThreadNameSet anyObject];
    }

    - (NSManagedObjectContext *)mainManagedObjectContext
    {
    [self managedObjectContext];
    return [mocs objectForKey:[self mainThreadName]];
    }

    - (void) destroyManagedObjectContextForThreadName:(NSString *)name
    {
    if (name != nil && [mocs objectForKey:name] != nil) {
    NSManagedObjectContext *moc = [mocs objectForKey:name];
    [moc release];
    moc = nil;
    [mocs removeObjectForKey:name];
    [mocThreads removeObjectForKey:name];
    }
    }

    - (void) destroyAllManagedObjectContexts
    {
    for (NSString *name in [mocs allKeys]) {
    [self destroyManagedObjectContextForThreadName:name];
    }
    }