Reputation: 9426
I'm building an Apple Watch app with a shared Core Data context between the iPhone target and the Watch's target via App Group. WatchCoreDataProxy
below is an custom framework that handles Core Data functions, referring to the App Group as a bridge between the two targets. I update the context in the iPhone app and save, then post a Darwin notification to the Watch which fetches the updated NSManagedObjects from the same context. Most everything is working well except for one quirk:
The NSManagedObject I'm fetching in the Watch (let's call it Parent
) contains a one-to-many relationship with another NSManagedObject (let's call it Child
). I'm fetching Parent
from within the Watch target with the assumption that it's properties have been saved to Core Data and reflect the most recent values.
The properties of Parent
always reflect the updated values when fetched from the Watch. However the Child
relationship object does not. What's really weird is that the changes to Child
persist on the iPhone app side of things, but not in the Watch. My code to fetch the object from the Watch looks like this:
let entityDesc = NSEntityDescription.entityForName("Parent", inManagedObjectContext: WatchCoreDataProxy.sharedInstance.managedObjectContext!)
let request: NSFetchRequest = NSFetchRequest()
request.entity = entityDesc
let predicate = NSPredicate(format: "loadedOnWatch == 1")
request.predicate = predicate
var error: NSError?
let array = WatchCoreDataProxy.sharedInstance.managedObjectContext!.executeFetchRequest(request, error: &error)! as NSArray
let parent: Parent = array[0] as! Parent
self.parentID = parent.objectID
self.parentTitleLabel.setText(parent.name) //reflects changes successfully
self.childArray = parent.children.sortedArrayUsingDescriptors([NSSortDescriptor(key: "position", ascending: true)]) as NSArray
let firstChild = self.intervalArray.objectAtIndex(0) as! Child
let title = firstChild.title
self.childTitleLabel.setText(title) //does not reflect changes
I've tried Core Data's refreshObject:mergeChanges:
method with no luck. Why does the Watch target not reflect the changes made to Child
in the same managed object context?
UPDATE
I found out by re-writing the above code that fetching the NSManagedObjects separately through two different NSFetchRequests, and then refreshing the objects yields the correct values. Here's the updated code:
// Parent fetch
let parentEntityDesc = NSEntityDescription.entityForName("Parent", inManagedObjectContext: WatchCoreDataProxy.sharedInstance.managedObjectContext!)
let parentRequest: NSFetchRequest = NSFetchRequest()
parentRequest.entity = parentEntityDesc
let parentPredicate = NSPredicate(format: "loadedOnWatch == 1")
parentRequest.predicate = parentPredicate
var parentError: NSError?
let array = WatchCoreDataProxy.sharedInstance.managedObjectContext!.executeFetchRequest(parentRequest, error: &parentError)! as NSArray
let parent: Parent = array[0] as! Parent
self.parentTitleLabel.setText(parent.name)
// Child fetch
let childEntityDesc = NSEntityDescription.entityForName("Child", inManagedObjectContext: WatchCoreDataProxy.sharedInstance.managedObjectContext!)
let childRequest: NSFetchRequest = NSFetchRequest()
childRequest.entity = childEntityDesc
let childPredicate = NSPredicate(format: "parent = %@", parent)
childRequest.predicate = childPredicate
let sort = NSSortDescriptor(key: "position", ascending: true)
childRequest.sortDescriptors = [sort]
var error: NSError?
self.childArray = WatchCoreDataProxy.sharedInstance.managedObjectContext!.executeFetchRequest(childRequest, error: &error)! as NSArray
let firstChild = self.childArray[0] as! Child
WatchCoreDataProxy.sharedInstance.managedObjectContext?.refreshObject(firstChild, mergeChanges: true)
let childTitle = firstChild.title
self.childTitleLabel.setText(childTitle)
So why would fetching the NSManagedObjects this way yield the correct values as opposed to relying on the Parent's relationship?
Upvotes: 0
Views: 243
Reputation: 3599
It depends on how your NSManagedContext's are structured. It's not enough to save changes to "some" NSManagedObject context in your iPhone app, because in the WatchKit Extension, there is actually different context (it's completely different app in different app container).
So you have to update the changes into Persistence Coordinator which actually saves them into a file in the app group container or into iCloud.
Upvotes: 3