核心数据:我应该从父上下文中获取对象还是子上下文与父上下文具有相同的对象?
Core Data: should I be fetching objects from the parent context or does the child context have the same objects as the parent?
我对 ManagedObjectContext
的 parent/child 上下文有点困惑。
当我设置子上下文并设置父上下文时,子上下文是否包含父上下文的所有对象?我正在使用在 AppDelegate
中创建的常用 Core Data
方法,但我将 ConcurrencyQueue
更改为 main.
在我应该更新数据库的方法中:
- 创建子上下文,设置父上下文
- 对子上下文执行阻止
- 从父上下文中获取
- 在子上下文中创建或更新对象
- 在子上下文中调用保存
- 有通知侦听器来处理子上下文保存
- 保存父上下文
我的问题是我似乎没有将任何内容保存到子上下文中。我没有收到 Update 或 Create ChatMessage 的 println 消息。我在这里做错了什么?
AppDelegate 核心数据方法
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()
}
}
处理更新的数据库class
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)
}
创建子上下文然后从父上下文中获取似乎没有太大意义。我不认为这是子上下文块的使用方式。
消除混淆:从父上下文创建子上下文后,该子上下文与父上下文具有相同的 "state"。只有当两个上下文做不同的事情(创建、修改、删除对象)时,两个上下文的内容才会不同。
因此,对于您的设置,请按以下步骤进行:
- 创建子上下文
- 做您想做的工作(从下载的数据修改或创建对象),
- 保存子上下文
在这个阶段,还没有任何东西被保存到持久存储中。使用子保存,更改只是对父上下文的 "pushed up"。您现在可以
- 保存父上下文
将新数据写入持久存储。那么
- 更新您的 UI、
最好通过通知(例如 NSManagedObjectContextDidSaveNotification
)。
我对 ManagedObjectContext
的 parent/child 上下文有点困惑。
当我设置子上下文并设置父上下文时,子上下文是否包含父上下文的所有对象?我正在使用在 AppDelegate
中创建的常用 Core Data
方法,但我将 ConcurrencyQueue
更改为 main.
在我应该更新数据库的方法中:
- 创建子上下文,设置父上下文
- 对子上下文执行阻止
- 从父上下文中获取
- 在子上下文中创建或更新对象
- 在子上下文中调用保存
- 有通知侦听器来处理子上下文保存
- 保存父上下文
我的问题是我似乎没有将任何内容保存到子上下文中。我没有收到 Update 或 Create ChatMessage 的 println 消息。我在这里做错了什么?
AppDelegate 核心数据方法
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()
}
}
处理更新的数据库class
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)
}
创建子上下文然后从父上下文中获取似乎没有太大意义。我不认为这是子上下文块的使用方式。
消除混淆:从父上下文创建子上下文后,该子上下文与父上下文具有相同的 "state"。只有当两个上下文做不同的事情(创建、修改、删除对象)时,两个上下文的内容才会不同。
因此,对于您的设置,请按以下步骤进行:
- 创建子上下文
- 做您想做的工作(从下载的数据修改或创建对象),
- 保存子上下文
在这个阶段,还没有任何东西被保存到持久存储中。使用子保存,更改只是对父上下文的 "pushed up"。您现在可以
- 保存父上下文
将新数据写入持久存储。那么
- 更新您的 UI、
最好通过通知(例如 NSManagedObjectContextDidSaveNotification
)。