核心数据:我应该从父上下文中获取对象还是子上下文与父上下文具有相同的对象?

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)。