WatchKit Core Data Sync Up
Asked Answered
E

3

4

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?

Event answered 6/1, 2015 at 3:20 Comment(0)
W
2

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"];
}
Watercourse answered 6/4, 2015 at 16:30 Comment(2)
I haven't looked at this project for a while but this was what I was thinking about attempting once I start working on it again. Possibly without MMWormhole.Event
Would love to see how this is done in Swift. Overriding initWithCoder does not seem to work as expected.Hell
L
1

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.

Laity answered 6/1, 2015 at 16:59 Comment(6)
Well my problem is a little more difficult I am using a NSFetchedResultsController and the callbacks are not being triggered in watchkit when my iOS app writes to Core Data. I think I my have to not use NSFetchedResultsController in watchkit I may just have to periodically perform fetches. Cause I am not trying to update an individual object but force the context to detect changes on the disk.Event
I doubt you will get get callbacks in your watch kit extension (though I could be wrong). I thought the callbacks came from the object context posting notifications rather than from it watching the data store for changes. If you are having issues with queries having stale data try changing the stalenessInterval on the NSManagedObjectContext to 0.Laity
Yeah I wont get the context notifications from the iOS app in my extension. I am thinking what I will do is either have the extension and the app send messages between each other or just periodically reset core data.I will take a look at the staleness value this may also help.Event
The application and the extension are running as two different processes. Core Data does not provide a way for two different processes to be aware of object, context or store changes.Towill
@Towill There is a way to send notifications between the extension and the app using Darwin notifications. Using these, you can reset Core Data when the notification occurs. I just do not know how to reset Core Data.Martsen
Give every context the -reset message.Towill
T
1

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.

Trehalose answered 29/1, 2015 at 13:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.