NSPersistentDocument FetchRequest warp 属性 在 macOS Document App SwiftUI 项目上崩溃

NSPersistentDocument FetchRequest warp property crash on macOS Document App SwiftUI project

  1. 使用 Xcode macOS Document App 模板创建项目,选中 Use Core Data 复选框。
  2. 将图书实体添加到 Document.xcdatamodeld
  3. 将 FetchRequest 扭曲 属性 添加到 ContentView
@FetchRequest(entity: Book.entity(), sortDescriptors: []) var books: FetchedResults<Book>
  1. 生成并运行、崩溃

来自控制台的崩溃日志是

2020-07-03 23:12:23.597880+0800 DocMacDemo[15236:4376209] [error] error: No NSEntityDescriptions in any model claim the NSManagedObject subclass 'DocMacDemo.Book' so +entity is confused.  Have you loaded your NSManagedObjectModel yet ?
CoreData: error: No NSEntityDescriptions in any model claim the NSManagedObject subclass 'DocMacDemo.Book' so +entity is confused.  Have you loaded your NSManagedObjectModel yet ?
2020-07-03 23:12:23.598287+0800 DocMacDemo[15236:4376209] [error] error: +[DocMacDemo.Book entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[DocMacDemo.Book entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
2020-07-03 23:12:23.644491+0800 DocMacDemo[15236:4376209] executeFetchRequest:error: A fetch request must have an entity.
2020-07-03 23:12:23.653769+0800 DocMacDemo[15236:4376209] [error] error: The fetch request's entity 0x600003500420 'Book' appears to be from a different NSManagedObjectModel than this context's
CoreData: error: The fetch request's entity 0x600003500420 'Book' appears to be from a different NSManagedObjectModel than this context's
(lldb)

几天来我一直在寻找 NSPersistentDocument SwiftUI 示例,但找不到。 这里有一些相似或相关的问题。可惜这个问题没有解决。

编辑: 上传本期项目到Github, https://github.com/donly/DocMacDemo.

这是因为新文档为空。与任何基于文档的应用程序一样,您必须为新文档准备一些默认的初始数据

这是可能的解决方案。使用 Xcode 11.4 / iOS 13.4

测试

在Document.swift

class Document: NSPersistentDocument {

    // .. other code here

    override func makeWindowControllers() {

        // in case of new document create new empty book in context
        // that will be shown in opened document window
        let isNew = self.fileURL == nil
        if isNew {
            _ = Book(context: self.managedObjectContext!)       // << here !!
        }

        let contentView = ContentView().environment(\.managedObjectContext, self.managedObjectContext!)

        // ... other code here

好吧,Asperi 的回答很好,但是在对象模型中留下了一本可能不需要的书。另一种方法是将上下文保存在 Asperi 建议的同一位置:

    if let context = managedObjectContext {
        try? context.save()
    }

那么 FetchRequest 也不会有错误信息。