Sharing Core Data between iPhone and Watch Apps
While developing Pitch X, I had to deal with an issue with the way Core Data and extensions work. In order to make the iPhone and Watch communicate and work alongside each other, I needed to make some interesting changes.
The first change I needed to make in order to share the Core Data store was to move it into an App Group. This allows any apps belonging to this group to access the files (the Watch app counts as its own entity in this case). To fully make this work, I needed to modify my Core Data code to store the files in this container, as well as point the persistent store coordinator into the right directory.
That part was relatively simple. However, one thing I noticed was that changes on one device would not show up on the other device until I restarted the app. This led to the user interfaces being in two different states on the different devices. Even worse, if I modified a Core Data entity on one device, then modified the same entity on another, the app crashes. Core Data doesn’t like you trying to save stale versions of entities in the store.
The only way to communicate between the two apps is to use Darwin notifications (something I did not even know existed until recently). So I used a custom class to allow my apps to communicate with each other using notifications — one notification telling the app to refresh, and another to tell the watch to refresh.
This appeared to work well, only it still had a big error. I would change the value on the phone, and the value would appear to change on the watch. However, if I then changed the value on the watch, it would crash.
After trying to figure out why the entities were still stale on the second device, I discovered that when you use Core Data in an app, it does not automatically do anything if the underlying store changes. The app has its own “copy” of the store held in memory (I don’t know if this is technically correct, but this is how it behaves).
When the Darwin notification was called, I needed to call managedObjectContext.reset() for the app to read the new values from the phone and be able to edit the entities without crashing.
I expect to see more complications having to do with the sandboxed environment iPhone and Watch apps live in. As of now, Watch apps are almost entirely dependent on their iPhone counterparts, though they seem to have been designed in a way that favors independence.
I’m interested to see how other developers go around these limitations.