Swift,安全又简单的另一个CoreData堆栈

微调NSPersistentContainer

我时不时地看到苹果公司的代码示例和模板提出了非最佳解决方案。 我发现苹果的代码有问题,CoreData在我列表的顶部。

您可以自己尝试。 创建包含CoreData的任何Xcode项目。 苹果公司的CoreData代码建议使用主线程(视图上下文)来保留数据。 最重要的是,它在AppDelegate中完成。 但是,Apple确实使用这种方法解决了写入冲突,因为我们仅使用一个上下文来保存数据,但是解决写入冲突还不够。

持久数据,无论保存多少数据,都比读取慢得多。 保存数据会执行SQLite COMMIT,即使您只写一个BYTE,也要花费几毫秒的时间。 在主线程上编写将使您的用户界面变得迟钝。

这就是为什么我将CoreData堆栈组织成这样的原因:

我假设您了解有关Apple的NSPersistentContainer全部知识,如果不了解,则需要进行检查。 您需要先设置它并加载存储,然后再创建CoreData堆栈。 在上面的代码中,我在其他文章中使用了一个简单的“变异运算符”。

在我们的基本CoreData堆栈中,我们有3个专用上下文:

  • mainContext只读主上下文,出于所有与UI相关的目的,它会自动观察更改。
  • writingContext读+写背景上下文,我们只在这里和这里保存数据,其他人只是观察。
  • readingContext只读的背景上下文,用于非UI用途,当我们必须对后台的更改做出反应时(并非每个人都需要此内容)。

我们从不对后台上下文使用performAndWait ,因为我们的块是在这些上下文的内部队列中异步执行的。 当我们想“关闭”核心数据栈时,我们需要等待内部队列完成后台任务。 这就是为什么我们将背景上下文包装到BackgroundManagedObjectContext并在deinit使用performAndWait取消所有未完成的任务的原因。 除此之外,应使用performTask扩展方法(这是对perform方法的包装)添加所有任务。

苹果提供了在此设置中应避免的方法

  func performBackgroundTask(_块:@转义(NSManagedObjectContext)->无效) 

问题是,如果使用此方法进行写操作,则会发生写冲突,因为每次都会使用其自己的内部串行队列创建一个新的上下文。