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?
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"];
}
I ran into the same issue. I used - (void)refreshObject:(NSManagedObject *)object mergeChanges:(BOOL)flag
in the NSManagedObjectContext to get the latest data for the managed object.
Ran into similar issues. Despite creating a shared Fetched Results Controller in the App Group observing Managed Object Context changes and refreshing Managed Object Context were not feasible.
Managed Object Contexts cache a certain level of the object graph for retrieval without reading from the actual SQLite store on the disk. The only potential way to actually get live sync between the two would be sending messages across iOS app to Extension when the MOC changes and destroying/rebuilding the Core Data stack from the disk every single time, not a great solution at all.
I believe the use case for live sync between iOS and Extension at initial launch isn't a necessity. Hopefully we get a more deliberate solution to this problem in a future release.