【问题标题】:SwiftUI FetchRequest Error: 'A fetch request must have an entity'SwiftUI FetchRequest 错误:“获取请求必须有一个实体”
【发布时间】:2020-12-03 13:35:16
【问题描述】:

我正在使用 SwiftUI 和 CoreData 以及 SwiftUI 应用程序生命周期(无场景或应用程序委托)构建一个小型应用程序。当我运行+构建我的应用程序时出现以下错误:

'executeFetchRequest:error: A fetch request must have an entity.'

我已经检查/验证/重新检查了以下内容:

  • 我的[app name].xcdatamodeld 文件名与我传入 NSPersistentContainer NSPersistentCloudKitContainer(name: [app name]) 的文件名相同
  • 实体名称 Car 正是我传递给 FetchRequest 的内容
@FetchRequest(entity: Car.entity(), sortDescriptors: []) var car: FetchedResults<Car>
  • 我正在为我的实体 Codegen 选择 Manual/None,生成的类是
public class Car: NSManagedObject {}

在 Car 上的扩展名为 Identifiable

这是我的整个视图结构,应该(据我理解)将环境传递给它的所有“子”视图。

struct AppView: View {
    
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: Car.entity(), sortDescriptors: []) var car: FetchedResults<Car>
    
    var body: some View {
        List {
            ForEach(car, id:\.self) { item in
                RootView(carData: item)
                    .environment(\.managedObjectContext, self.moc)
            }
        }
    }
}

还有我的@main 结构

@main
struct AutoMateApp: App {
    
    @StateObject var coreData = PersistentCloudKitContainer()
    
    let persistence = PersistentCloudKitContainer()
    
    var body: some Scene {
        WindowGroup {
            AppView()
                .environment(\.managedObjectContext, coreData.persistentContainer.viewContext)
        }
    }
}

当我使用调试器单步执行时,一旦返回 WindowGroup,就会出现崩溃。我不确定这是否是有用的信息。

感谢您的所有帮助,谢谢。

【问题讨论】:

  • 我遇到了完全相同的问题。但我正在为我的核心数据类使用 Xcode 代码生成。你找到解决办法了吗?

标签: swift core-data swiftui


【解决方案1】:

好的,所以从AppDelegate 中的lazy var persistentContainer: NSPersistentCloudKitContainer = {...}() 行中删除lazy 对我的情况有帮助。因为似乎 Apple 的样板代码在 let contentView = ContentView().environment(\.managedObjectContext, persistentContainer.viewContext) 行中传递了 NSManagedObjectModel 并且 FetchRequest 在它被闭包正确实例化之前访问了该对象,因此无法找到 NSManagedObject subclass。从变量中删除lazy 会立即执行闭包。

希望这仍然可以帮助您并解决您遇到的问题。

【讨论】:

  • 感谢您的回复。 Apple 终于向我们展示了他们对 CoreData 如何与他们眼中的 SwiftUI 生命周期应用程序一起工作的实现。这出现在 Xcode 12 beta 6 中。从那以后我就使用了它,并且我的应用程序流动方式略有不同,从而解决了我的问题。
【解决方案2】:

Car.entity() 替换为静态 NSEntityDescription。

例子

struct AppView: View {
    
    @Environment(\.managedObjectContext) var moc
    @FetchRequest(entity: AppView_Previews.entity, sortDescriptors: []) var car: FetchedResults<Car>
    
    var body: some View {
        List {
            ForEach(car, id:\.self) { item in
                RootView(carData: item)
                    .environment(\.managedObjectContext, self.moc)
            }
        }
    }
}

struct AppView_Previews: PreviewProvider {
    static var entity: NSEntityDescription {
        return NSEntityDescription.entity(forEntityName: "Car", in: yourViewContext)!
    }
}

【讨论】:

    【解决方案3】:

    在选中 Core Data 支持时尝试 SwiftUI 应用项目模板中的代码:

    MyApp.swift

    import SwiftUI
    
    @main
    struct MyApp: App {
        let persistenceController = PersistenceController.shared
    
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .environment(\.managedObjectContext, persistenceController.container.viewContext)
            }
        }
    }
    

    Persistance.swift

    import CoreData
    
    struct PersistenceController {
        static let shared = PersistenceController()
    
        static var preview: PersistenceController = {
            let result = PersistenceController(inMemory: true)
            let viewContext = result.container.viewContext
            for _ in 0..<10 {
                let newItem = Item(context: viewContext)
                newItem.timestamp = Date()
            }
            do {
                try viewContext.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
            return result
        }()
    
        let container: NSPersistentContainer
    
        init(inMemory: Bool = false) {
            container = NSPersistentContainer(name: "MyApp")
            if inMemory {
                container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
            }
            container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                if let error = error as NSError? {
                    // Replace this implementation with code to handle the error appropriately.
                    // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
    
                    /*
                    Typical reasons for an error here include:
                    * The parent directory does not exist, cannot be created, or disallows writing.
                    * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                    * The device is out of space.
                    * The store could not be migrated to the current model version.
                    Check the error message to determine what the actual problem was.
                    */
                    fatalError("Unresolved error \(error), \(error.userInfo)")
                }
            })
        }
    }
    

    【讨论】:

    • 感谢您的回复。由于这个问题是在 Xcode 12 beta 6 之前提出的,Apple 还没有这个样板模板。从 beta 6 开始,我无论如何都对我的应用程序使用了不同的方法。我很感激帮助。编辑:将此标记为正确答案,因为它确实表明了我在 beta 6 发布后开始做的事情。
    猜你喜欢
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 2021-03-01
    相关资源
    最近更新 更多