【问题标题】:How to deal with concurrency on core data如何处理核心数据的并发
【发布时间】:2018-12-11 14:58:47
【问题描述】:

我一直在谷歌、stackoverflow 和互联网上徘徊,试图了解如何处理核心数据和处理并发性。

假设我们有 2 张桌子,活动和房间。 一个活动可以有 1 个以上的房间。

FunctionA - 添加事件

FunctionB - 添加房间

FunctionC - SearchRoom -> 返回 RoomEntity 或 nil

我的问题,我不断收到这些错误

Error Domain=NSCocoaErrorDomain Code=133020 "Could not merge changes." UserInfo={conflictList=(
    "NSMergeConflict (0x10a507160) for NSManagedObject (0x1092f00c0) with objectID '0xd000000000040000 <x-coredata://A34C65BD-F9F0-4CCC-A9FB-1B1F5E48C70E/Rooms/p1>' with oldVersion = 116 and newVersion = 124 and old object snapshot = {\n    location = Lisboa;\n    name = \"\\U00cdndico LX\";\n} and new cached row = {\n    location = Lisboa;\n    name = \"\\U00cdndico LX\";\n}"

注意房间的信息是相等的

我的方法如下。

1-我调用了一次webservice(它带来了一个json,其中包含3种事件的数据)这3个都具有相同的json结构并共享由参数传递的相同的managedObjectContext

2- 我创建了一个托管对象

var managedObjectContext: NSManagedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext = persistentContainer.viewContext
managedObjectContext.parent?.mergePolicy = NSMergePolicyType.mergeByPropertyObjectTrumpMergePolicyType

3-

 managedObjectContext.perform(
        {
            do
            {

                try self.deleteAllEventsFromDb()

                FunctionA(eventList, managedObjectContext) -> save
                FunctionA(eventList2, managedObjectContext) -> save
                FunctionA(eventList3, managedObjectContext) -> save

                self.DatabaseDispatchGroup.enter()
                try managedObjectContext.save()
                self.DatabaseDispatchGroup.leave()
                completion(Result.Success(true))
            } 
            catch let error as NSError
            {
                print("Could not save. \(error), \(error.userInfo)")
                completion(Result.Success(false))
            }
      })

4- 对于每个事件,我执行相同的 FunctionA 以在数据库 (managedObjectContext.insert(eventEntity)) 中创建和保存数据。这将适用于几个表,但我们只考虑事件和房间(FunctionB)。

5- 函数A 包含函数B。函数 B 搜索现有 Room(FunctionC->返回实体?)如果不存在(nil),则创建实体(我应该保存在这里吗?)

6- 如果 Room 存在,获取实体并尝试更新数据

不确定它是否有任何区别,但是当我保存时,我会在 dispatchGroup 之间进行这些保存

DatabaseDispatchGroup.enter()
try managedObjectContext.save()
DatabaseDispatchGroup.leave()

我使用的是用于所有数据库请求的静态 managedObjectContext,但现在我决定为每个访问数据库的函数创建一个 objectContext。

我确实为所有请求保留相同的 persistentContainer 和相同的 DispatchGroup

private override init() {
persistentContainer = NSPersistentContainer(name: "DataModel")

        persistentContainer.loadPersistentStores() { (description, error) in
            if let error = error {
                fatalError("Failed to load Core Data stack: \(error)")
            }

        }
}

在我看来,我的问题是我将更改存储在内存中,并且总是对初始数据进行更新,这意味着当我执行 save() 时,上下文不会为下一次操作更新数据?

我应该如何/何时执行保存功能?

谢谢

【问题讨论】:

  • 您可以在核心数据中使用父子模式进行并发developmentnow.com/2015/04/28/…
  • 我的第一种方法是使用静态 MOC,但它不起作用,我仍然遇到并发问题。我认为这是因为我将 DispatchGroup 与 .perform 混合在一起(我认为它们的目标相同)。因此,如果我将静态 MOC 与 .perform 一起使用,它应该可以正常工作吗?

标签: swift xcode core-data concurrency


【解决方案1】:

一旦保存上下文,就会发布全局通知:ContextDidSave 通知。

当使用多个上下文(而不是使用父子方法)时,您应该使用此通知以及:

  • 重新获取/刷新数据,以防您需要更新视图或对新数据集执行某些操作(使用获取请求或 refreshObjects: API)。
  • 将更改合并到其他上下文(请记住线程限制!仅在适当的上下文队列上执行此操作)。 (merge doc)

有很多关于它的文章,例如this tutorialdocumentation

【讨论】:

  • 我的想法是 dispatchGroup 被用来防止同时发生多个请求。 :P 我错了
猜你喜欢
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 2018-01-02
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多