Search code examples
ioscore-datasynchronizationwatchkit

WatchKit Core Data Sync Up


I have an app structured as follows

iOS App Writes data to Core Data which has a persistent store stored in a shared app group.

The Watch Kit extension is able to read data from Core Data that was written by the iOS app.

The issue I am having is if my iOS app writes data while my watch kit app is open I am not getting updates because the object context is not syncing with the data on the disk.

Is there a way that since my watch kit extension is only reading data to be able to refresh the context and force it to load again from the data on the disk?


Solution

  • My working solution was using MMWormhole to send notification (NSManagedObjectContextDidSaveNotification) from iPhone app to my watch app. In the watch app's controller i used mergeChangesFromContextDidSaveNotification: method of NSManagedObjectContext.

    // in iPhone app's notification handler
    MMWormhole *wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"your.group.container.identifier" optionalDirectory:nil];
    [wormhole passMessageObject:notification identifier:@"your notification identifier"];
    
    // in WKInterfaceController's awakeWithContext: method
    MMWormhole *wormhole = [[MMWormhole alloc] initWithApplicationGroupIdentifier:@"your.group.container.identifier" optionalDirectory:nil];
    [wormhole listenForMessageWithIdentifier:@"your notification identifier" listener:^(id messageObject) {
        [self.managedObjectContext mergeChangesFromContextDidSaveNotification:messageObject];
    }];
    

    Then NSFetchedResultsController did all other work with UI updates.

    You must implement initWithCoder: and encodeWithCoder: methods from NSCoding protocol for your NSManagedObject subclasses because MMWormhole uses NSKeyedArchiver as a serialization medium.

    - (id)initWithCoder:(NSCoder *)decoder {
        NSManagedObjectContext *context = ... // use your NSManagedObjectContext 
        NSPersistentStoreCoordinator *coordinator = ...; //use your NSPersistentStoreCoordinator
        NSURL *url = (NSURL *)[decoder decodeObjectForKey:@"URIRepresentation"];
        NSManagedObjectID *managedObjectID = [coordinator managedObjectIDForURIRepresentation:url];
        self = [context existingObjectWithID:managedObjectID error:nil];
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)encoder {
        [encoder encodeObject:[[self objectID] URIRepresentation] forKey:@"URIRepresentation"];
    }