【问题标题】:Using @fetchRequest(entity: ) for SwiftUI macOS app crashes使用 @fetchRequest(entity:) 处理 SwiftUI macOS 应用程序崩溃
【发布时间】:2020-03-06 17:04:17
【问题描述】:

我正在尝试使用 Core Data 为 macOS 运行一个基本的测试 SwiftUI 应用程序,但我遇到了一个问题。当我在我看来使用它时:

@FetchRequest(entity: Note.entity(), sortDescriptors: []) let notes: FetchedResults<Note>

应用程序崩溃并出现以下错误:

NoteTaker [error] error: No NSEntityDescriptions in any model claim the NSManagedObject subclass 'NoteTaker.Note' so +entity is confused.  Have you loaded your NSManagedObjectModel yet ?
CoreData: error: No NSEntityDescriptions in any model claim the NSManagedObject subclass 'NoteTaker.Note' so +entity is confused.  Have you loaded your NSManagedObjectModel yet ?

NoteTaker [error] error: +[NoteTaker.Note entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass
CoreData: error: +[NoteTaker.Note entity] Failed to find a unique match for an NSEntityDescription to a managed object subclass

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

现在,如果我使用 FetchRequest 的替代形式,它可以正常工作,尽管代码更难看:

// outside of the view
func getAllNotes() -> NSFetchRequest<Note> {
  let request: NSFetchRequest<Note> = Note.fetchRequest()
  request.sortDescriptors = []
  return request
}

// in the view
@FetchRequest(fetchRequest: getAllNotes()) var notes: FetchedResults<Note>

另外,如果我把它变成一个 iOS 应用程序,那么 @FetchRequest 的实体版本可以正常工作。

有什么想法吗?

【问题讨论】:

  • 在写这篇文章时,我发现如果我在 AppDelegate 中更改自动生成的 persistantContainer 代码,让它不再懒惰,那么它就可以工作了。因此,在 fetchRequest 的实体样式生成之前,容器没有被实例化似乎是一个问题。虽然这是一个修复,但它有点笨拙,因为显然我们只想在真正需要时处理实例化持久容器的成本,而不是在应用程序加载时(因此它是惰性的)。此外,当 Apple 为您自动创建时,它与它背道而驰,这感觉真的很糟糕。
  • 你解决了这个问题吗?
  • 解决了什么问题?
  • 在自动生成的 AppDelegate.swift 中删除“// MARK: - Core Data stack”下面的“lazy”也对我有用。浪费了很多时间。
  • 如果你仔细想想,这完全有道理。应用程序委托创建 ContentView(),然后使用 environment(\.managedObjectContext, persistentContainer.viewContext) 对其进行修改。因此,在使用其@FetchRequest 属性创建 ContentView 之后,会延迟创建持久化容器。如果您要在主体内部创建一个具有@FetchRequest 属性的视图,那也可以,因为稍后会调用主体。

标签: swift macos core-data swiftui


【解决方案1】:

我在获取和动态获取请求的代码以及创建核心数据对象时的多个地方都遇到了这个错误,这对我有用:

在获取请求期间,我使用了这个:

@FetchRequest(entity: NSEntityDescription.entity(forEntityName: "Your Entity Name", in: managedObjectContext), sortDescriptors: [NSSortDescriptor(key: "Your Key", ascending: true)])

在动态获取请求中我使用了这个:

var entity: Entity
var fetchRequest: FetchRequest<Your Entity>
init(_ entity: Entity) {
self.entity = entity
self.fetchRequest = FetchRequest(entity: NSEntityDescription.entity(forEntityName: "Your Entity", in: managedObjectContext), sortDescriptors: [NSSortDescriptor(key: "Your Key", ascending: true)], predicate: NSPredicate(format: "entity.uniqueIdentifier == %@", entity.uniqueIdentifier!))
}

var youEntities: FetchedResults<Your Entity> {
fetchRequest.wrappedValue
}

创建核心数据对象时:

let entityDescription = NSEntityDescription.entity(forEntityName: "Your Entity", in: managedObjectContext)

let object = Your Entity(entity: entityDescription!, insertInto: managedObjectContext)

【讨论】:

  • 使用 NSEntityDescription.entity(forEntityName: "Your Entity Name", in: managedObjectContext) 为我工作!
【解决方案2】:

使用 Storyboard 模板,然后在视图控制器中使用 SwiftUI 设置视图。

override func viewWillAppear() {
        super.viewWillAppear()

        let context = (NSApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let contentView = ContentView().environment(\.managedObjectContext, context)

        view = NSHostingView(rootView: contentView)
    }

【讨论】:

    【解决方案3】:

    添加这一行: .environment(.managedObjectContext, context)

    在 SceneDelegate.swift 中

    // Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
    // Add `@Environment(\.managedObjectContext)` in the views that will need the context.
    let contentView = ContentView().environment(\.managedObjectContext, context)
    

    【讨论】:

      猜你喜欢
      • 2020-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多