I am slightly confused about parent/child contexts for ManagedObjectContext
.
When I setup a child context and set the parent context, does the child context contain all the objects of the parent context? I am using the stock Core Data
methods that get created in the AppDelegate
, but I changed the ConcurrencyQueue
to main.
In my method that is supposed to update the db:
- Create child context, set parent context
- Perform block on child context
- Fetch from parent context
- Create or update object in child context
- Call save on child context
- Have Notification listener to handle child context saves
- Save parent context
My issue is that it does not look I am saving anything to the child context. I am not getting my println messages of Update or Create ChatMessage. What am I doing wrong here?
AppDelegate Core Data methods
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
NSNotificationCenter.defaultCenter().addObserver(self, selector: "contextDidSave:", name: NSManagedObjectContextDidSaveNotification, object: nil)
return managedObjectContext
}()
func contextDidSave(notification: NSNotification) {
let sender = notification.object as! NSManagedObjectContext
if sender != managedObjectContext {
managedObjectContext?.mergeChangesFromContextDidSaveNotification(notification)
println("Core Data: merging changes from child context")
saveContext()
}
}
Database class that handles the update
lazy var parentContext: NSManagedObjectContext? = {
if let managedObjectContext = self.appDelegate.managedObjectContext {
return managedObjectContext
}
else {
return nil
}
}()
func updateMessage(chatMessage: ChatMessage) {
if chatMessage.id.isEmpty { return }
let childContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
childContext.parentContext = parentContext
childContext.performBlock({
let objectIdDesc = NSExpressionDescription()
objectIdDesc.name = "objectID"
objectIdDesc.expression = NSExpression.expressionForEvaluatedObject()
objectIdDesc.expressionResultType = NSAttributeType.ObjectIDAttributeType
let fetchRequest = NSFetchRequest(entityName: "ChatMessage")
fetchRequest.predicate = NSPredicate(format: "id == %@", chatMessage.id)
fetchRequest.propertiesToFetch = [objectIdDesc]
fetchRequest.resultType = .DictionaryResultType
var error: NSError?
if let results = self.parentContext!.executeFetchRequest(fetchRequest, error: &error) {
if error == nil {
if !results.isEmpty {
if let objectId = results[0].valueForKey("objectID") as? NSManagedObjectID {
let fetched = childContext.objectWithID(objectId) as! ChatMessage
fetched.id = chatMessage.id
fetched.senderUserId = chatMessage.senderUserId
fetched.senderUsername = chatMessage.senderUsername
fetched.receiverUserId = chatMessage.receiverUserId
fetched.receiverUsername = chatMessage.receiverUsername
fetched.messageType = chatMessage.messageType
fetched.message = chatMessage.message
fetched.timestamp = chatMessage.timestamp
fetched.filepath = chatMessage.filepath
println("Updated ChatMessage: \(fetched.id)")
}
else {
var newMessage = NSEntityDescription.insertNewObjectForEntityForName("ChatMessage", inManagedObjectContext: childContext) as! ChatMessage
newMessage.id = chatMessage.id
newMessage.senderUserId = chatMessage.senderUserId
newMessage.senderUsername = chatMessage.senderUsername
newMessage.receiverUserId = chatMessage.receiverUserId
newMessage.receiverUsername = chatMessage.receiverUsername
newMessage.messageType = chatMessage.messageType
newMessage.message = chatMessage.message
newMessage.timestamp = chatMessage.timestamp
newMessage.filepath = chatMessage.filepath
println("Create ChatMessage: \(newMessage.id)")
}
}
}
else {
println("Fetch Message Object ID Error: \(error?.localizedDescription)")
}
}
})
childContext.save(nil)
}