为了有效地问我的问题,让我们首先考虑一下我面临的确切情况:
常规设置
- 一个主机 iOS 8 应用程序。
- 与主机应用程序捆绑的一个或多个 iOS 8 扩展(WatchKit、Share 等)。
- 宿主应用程序和所有扩展程序在共享应用程序组容器中共享相同的 Core Data SQLite 存储。
- 每个应用/扩展都有自己的 NSPersistentStoreCoordinator 和 NSManagedObjectContext。
- 每个持久存储协调器都使用一个持久存储,该持久存储与所有其他持久存储在组容器中共享相同的 SQLite 资源。
- 该应用程序和所有扩展程序使用一个通用代码库来同步来自 Internet 上的远程 API 资源的内容。
导致问题的事件顺序
用户启动主机应用程序。它开始从远程 API 资源中获取数据。核心数据模型对象是基于 API 响应创建的,并“更新”到主机应用的托管对象上下文中。每个 API 实体都有一个唯一ID,用于在远程 API 后端标识它。“upsert”是指对于每个 API 实体,如果找不到给定 uniqueID 的现有条目,主机应用程序只会在 Core Data 中创建一个新条目。
同时,用户还启动了主机应用程序的扩展之一。它也从同一个远程 API 执行某种获取。它还尝试在解析 API 响应时执行“更新插入”。
问题:如果宿主应用程序和扩展程序都尝试同时为同一个 API 实体更新核心数据条目,会发生什么?要了解这是如何发生的,让我们看一下 upsert 的事件序列:
核心数据更新序列:
- API 解析代码解析给定 API 实体的唯一 ID。
- 解析器对任何匹配谓词的条目执行核心数据提取,其中谓词
uniqueID
等于解析的唯一ID。 - 如果未找到现有条目,则解析器为此 API 实体插入一个新的核心数据条目,将其
uniqueID
属性设置为解析的唯一 ID。 - 解析器保存托管对象上下文,它将新条目数据下推到 SQLite 后备存储。
详细问题
假设主机应用程序和扩展程序同时独立解析同一 API 实体的 API 响应。如果主机应用程序和扩展程序在它们中的任何一个完成第 4 步之前都到达第 3 步,那么它们都将尝试为相同的 uniqueID 插入新的 Core Data 条目。当他们到达第 4 步并调用save:
各自的托管对象上下文时,Core Data 将愉快地创建重复条目。
据我所知,Core Data 没有任何方法可以将属性标记为唯一。我需要一个相当于SQLite INSERT OR IGNORE
+UPDATE
组合的核心数据。. 否则我需要一种方法来“锁定”持久存储的 SQLite 后备存储,这听起来像是一个麻烦的秘诀。
是否有已知的方法来解决 iOS 8 扩展引入的这个相当新颖的问题?