Search code examples
simperium

NSManagedObjectContextDidSaveNotification and Simperium


I am not getting NSManagedObjectContextDidSaveNotification notifications from the NSManagedObjectContext I give to Simperium.

Basically what I like to do is inform my application when an update of the database has happened due to an update by simperium.

Therefore I am using 2 NSManagedObjectContexts, one for my application and the other one for Simperium. Once my application saves its context, the changes are merged to the simperium context in the NSManagedObjectContextDidSaveNotification notification via mergeChangesFromContextDidSaveNotification:.

The problem however is that whenever there is an update to the Simperium NSManagedObjectContext, I don't get a NSManagedObjectContextDidSaveNotification and thus I can't merge the changes from remote to my application context. I checked that it actually save the data to the persistent store.

Some code:

- (void) setSyncingEnabled:(BOOL)syncingEnabled
{
    if (syncingEnabled && !self.simperium)
    {
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(syncingObjectContextDidSaveNotification:)
                                                     name:NSManagedObjectContextDidSaveNotification
                                                   object:self.syncingObjectContext];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(objectContextDidSaveNotification:)
                                                     name:NSManagedObjectContextDidSaveNotification
                                                   object:self.objectContext];

        self.simperium = [[Simperium alloc] initWithRootViewController:App.delegate.window.rootViewController];
        self.simperium.authenticationOptional = YES;
        [self.simperium addDelegate:self];

        [self.simperium startWithAppID:kSimperiumAppId
                                APIKey:kSimperiumAPIKey
                                 model:self.objectModel
                               context:self.syncingObjectContext
                           coordinator:self.storeCoordinator];
    }
    else if (self.simperium) {
        self.simperium = nil;

        [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.syncingObjectContext];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.objectContext];
    }
}


- (void) objectContextDidSaveNotification:(NSNotification*)notification
{
    if (self.simperium) {
        [self.syncingObjectContext mergeChangesFromContextDidSaveNotification:notification];
    }
}

- (void) syncingObjectContextDidSaveNotification:(NSNotification*)notification
{
    [self.objectContext mergeChangesFromContextDidSaveNotification:notification];

    /* Inform Application */
    [[NSNotificationCenter defaultCenter] postNotificationName:DatabaseDidUpdateExternallyNotification object:self];
}

Solution

  • Since your goal is to inform your app when an update has happened via Simperium, there are better options than using a separate context (which Simperium does internally anyway):

    1) You can use an NSFetchedResultsController which will get called as objects are inserted, changed, and removed.

    2) You can use SimperiumDelegate to react to specific changes. This works a bit differently in the release that is currently being tested in the "iosupdate" branch on GitHub. The SimperiumDelegate protocol will be replaced by SPBucketDelegate to give you more control over the notifications you care about.

    If for some reason you really need to use a second context, please get in touch so we can talk about your use case a little more.