当前位置: 首页 > 面试题库 >

NSPersistentContainer并发用于保存到核心数据

潘辰龙
2023-03-14
问题内容

我读过一些博客,但是我仍然对如何使用NSPersistentContainer
performBackgroundTask创建实体并保存它感到困惑。通过init(context moc: NSManagedObjectContext)performBackgroundTask() { (moc) in }块中调用便捷方法创建实例后,如果检查是否container.viewContext.hasChanges返回false并说没有要保存的内容,如果我调用save
moc(为此块创建的后台MOC),则会收到如下错误:

fatal error: Failure to save context: Error Domain=NSCocoaErrorDomain

Code=133020 “Could not merge changes.” UserInfo={conflictList=(
“NSMergeConflict (0x17466c500) for NSManagedObject (0x1702cd3c0)
with objectID ‘0xd000000000100000
‘ with
oldVersion = 1 and newVersion = 2 and old cached row = {id = 2; … }fatal
error: Failure to save context: Error Domain=NSCocoaErrorDomain Code=133020
“Could not merge changes.” UserInfo={conflictList=(
“NSMergeConflict (0x170664b80) for NSManagedObject (0x1742cb980)
with objectID ‘0xd000000000100000
‘ with
oldVersion = 1 and newVersion = 2 and old cached row = {id = 2; …} and new
database row = {id = 2; …}”
)}

因此,我无法使并发正常工作,如果有人可以向我解释在iOS 10中对核心数据使用此功能的正确方法,我将非常感谢


问题答案:

TL:DR :您的问题是您同时使用viewContext和背景环境进行编写。您只应以一种同步方式写入核心数据。

完整说明:
如果在两个不同的上下文中同时更改了一个对象,则核心数据将不知所措。您可以设置mergePolicy来设置应赢的变更,但这并不是一个好的解决方案,因为您可能会丢失数据。许多专家长期以来一直在处理该问题,其方式是让操作队列将写操作排队,因此一次仅执行一次写操作,而在主线程上仅允许读操作拥有另一个上下文。这样,您就永远不会遇到任何合并冲突。(有关此设置的详细说明,请参见https://vimeo.com/89370886)。

进行此设置NSPersistentContainer非常容易。在您的核心数据管理器中,创建一个NSOperationQueue

//obj-c
_persistentContainerQueue = [[NSOperationQueue alloc] init];
_persistentContainerQueue.maxConcurrentOperationCount = 1;

//swift
let persistentContainerQueue = OperationQueue()
persistentContainerQueue.maxConcurrentOperationCount = 1

并使用此队列进行所有写操作:

// obj c
- (void)enqueueCoreDataBlock:(void (^)(NSManagedObjectContext* context))block{
  void (^blockCopy)(NSManagedObjectContext*) = [block copy];

  [self.persistentContainerQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{
    NSManagedObjectContext* context = self.persistentContainer.newBackgroundContext;
    [context performBlockAndWait:^{
      blockCopy(context);
      [context save:NULL];  //Don't just pass NULL here, look at the error and log it to your analytics service
     }];
  }]];
}

 //swift
func enqueue(block: @escaping (_ context: NSManagedObjectContext) -> Void) {
  persistentContainerQueue.addOperation(){
    let context: NSManagedObjectContext = self.persistentContainer.newBackgroundContext()
      context.performAndWait{
        block(context)
        try? context.save() //Don't just use '?' here look at the error and log it to your analytics service
      }
    }
}

调用时,enqueueCoreDataBlock该块将排队,以确保没有合并冲突。但是,如果您写入,viewContext那将破坏此设置。同样,您应该将您创建的任何其他上下文(使用newBackgroundContext或使用performBackgroundTask)视为只读,因为它们也将不在编写队列中。

起初我以为
NSPersistentContainerperformBackgroundTask有一个内部队列,并初步测试支持这一点。经过更多测试后,我发现它也可能导致合并冲突。



 类似资料:
  • 为了更新核心数据中的数据(当核心数据中已经有数据时),我删除了所有数据,然后重新插入数据。但我不知道为什么会发生合并冲突。我对核心数据还不熟悉,所以我也搞不清楚它到底出了什么问题。我想我需要更改我的deleteAll函数,但我不知道该更改什么。 代码如下。 我可以使用saveContext来保存核心数据,但我也需要更改位置,并且在重新启动后它不起作用。重新启动后,元素的顺序就像我第一次设置的一样。

  • 问题内容: 我知道我可以使用@distinctUnionOfObjects在SQL中找到类似以下内容的东西: 我正在寻找的是数组中返回的 所有数据 ,而不仅仅是与按表达式匹配的值的数组。本质上,我在寻找与以下SQL查询等效的核心数据: 问题答案: 这是模拟的 : 在这里找到

  • 我有5台设备连接到物联网集线器。此设备发送消息,我已将此消息保存到Azure存储表not blob。 我是根据这本指南做任何事情的https://blog.maximerouiller.com/post/persisting-iot-device-messages-into-cosmosdb-with-azure-functions-and-iot-hub/不幸的是,我可以毫无问题地添加输入和输出

  • 问题内容: 美好的一天,我正在尝试从表单中发送或获取数据,然后使用jquery和ajax将数据发送到应保存在数据库中的php页面中,如何在jquery中使用ajax来做到这一点,任何帮助会做的,谢谢! HTML页面1,它将使用jquery ajax将数据发送到php页面 PHP页面2将从页面1表单中接收数据 这个项目的任何帮助将极大地帮助我们,谢谢! (更新)这是我尝试使用的jQuery,但它转到

  • 当我的数据库用“photo_url”字段更新时,我想下载图像并将其保存到存储区

  • 我想知道,当我们为客户提供新的更新时,是否有丢失这些文件的风险。如果有更好的解决方案,上传文件和获取文件链接之后,与.NET core请告诉我:)