'类' className'的NSManagedObject必须有一个有效的NSEntityDescription。'错误

时间:2017-08-01 09:50:55

标签: swift core-data

我创建了简单的实体' CDWorkout'有一个属性' name'在CDModel.xcdatamodeld中。 AppDelegate中容器的名称也是“CDModel'”。用于' CDWorkout'的类Codegen是类别/扩展。这是CDWorkout类的代码:

class CDWorkout: NSManagedObject {

    class func createWorkout(workoutInfo : Workout, in context: NSManagedObjectContext) -> CDWorkout{
        let workout = CDWorkout(context: context)
        workout.name = "anyName"
        return workout
    }
}

createWorkout函数从另一个viewController调用,上下文参数为container.viewContext,但它会立即崩溃并显示消息:

  

由于未捕获的异常而终止应用程序' NSInvalidArgumentException',原因:'类的' Workout_Generator.CDWorkout'的NSManagedObject必须有一个有效的NSEntityDescription。'

我忘记了什么?

17 个答案:

答案 0 :(得分:16)

问题是我没有检查类模块:CDWorkout Entity的当前产品模块。

答案 1 :(得分:8)

在我的情况下,同样的问题出现在自动生成的数据类头中的@objc修饰符

@objc(CachedMovie)
public class CachedMovie: NSManagedObject {

我刚刚删除@objc(CachedMovie)并开始工作

答案 2 :(得分:6)

我有一个愚蠢的小问题,导致同样的错误。我用不正确的名称初始化NSPersistentContainer。

它应与源文件的名称相同,扩展名为 .xcdatamodeld 。例如 modelFileName.xcdatamodelId

let persistentContainer = NSPersistentContainer(name: "modelFileName")

答案 3 :(得分:4)

尝试从扩展程序(SiriKit)插入/添加托管对象时,我遇到了同样的错误消息。这似乎是扩展名称空间与.xcdatamodeld文件不匹配的问题,因为我使用MyClass.entity()创建了实体描述。

对我有用的组合是:

  • @objc(MyClass)位于每个NSManagedObject子类
  • 的顶部
  • 数据模型中的实体使用默认的"全局命名空间",而不是"当前产品模块"
  • 使用let entity = NSEntityDescription.entity(forEntityName: "MyClass", in: context)!
  • 创建实体说明

答案 4 :(得分:3)

发生这种情况的一种方法是尝试重命名您的实体。确保这些相同!

答案 5 :(得分:1)

我遇到了同样的问题。就我而言,我使用了在框架中初始化和管理的 CoreData,我通过 SPM 与主应用程序集成。

解决方案

首先,在框架中手动为实体提供模块名称,步骤如下:

  1. 打开 .xcdatamodel,
  2. 选择要编辑的实体,
  3. 打开数据模型检查器(右侧边栏中的第四个面板),
  4. 在部分 Class 元素模块默认呈现当前产品模块 -- 在此处输入您的模块名称

对每个实体重复这些步骤。

其次,在框架中为您在项目中使用的每个 NSManagedObject 覆盖 description,f.ex。你有:

public class Person: NSManagedObject {

}

使用没有模块名称的字符串覆盖那里的描述,例如:

public class Person: NSManagedObject {

    public override var description: String {
        return "Person"
    }
}

如果您对使用 Person(context: Context) 指定 description 的 Person 使用便利初始化程序(如 Person.entity()),上述代码将有所帮助。

答案 6 :(得分:1)

我在使用 Swift 包管理器导入一个包含模型文件作为资源的 Swift 包时遇到了这个问题。在我的情况下,将实体的模块设置为 Current Production Module 在模型文件中产生了不正确的值。当我在加载持久性容器后使用调试器打印模型时,完全限定的类名类似于 Module_Module.Class 而不是预期的 Module.Class。我不得不手动输入模块名称而不是使用 Current Production Module 来解决问题。

答案 7 :(得分:1)

对我来说,我忘记在下面的例子中添加@objc(Reminder)。我以编程方式编写了 NSManagedObject 类。

@objc(Reminder)
public class Reminder: NSManagedObject {


}

答案 8 :(得分:1)

如果您要使用静态库中的coreData,请确保同时指定模块

enter image description here

这为您提供了正确的实体访问权限MyStaticLibrary.MyManagedObject

因此,如果您收到带有该点符号的警告,则表示它不在您的模块中

答案 9 :(得分:1)

enter image description here在文件模型中 可能是因为班级名称不正确,原因是您在班级名称中更改了名称

答案 10 :(得分:0)

我犯的错误是更改实体名称和生成的“ NSManagedObject子类”,而不更新类的名称。解决方法:

  • 打开.xcdatamodeld
  • 点击实体
  • 打开右侧面板
  • 转到数据模型检查器
  • 更改“班级”文本字段的名称

答案 11 :(得分:0)

很容易回答这个问题。未被删除

@objc(Workout)

解决方案位于“ 实体名称和类名称”上的纪录片Core Data Programming上。 在执行此操作之前,在Xcode中点击此处(编辑器-> 创建NSManagedObject子类) 必须更改您的实体类名称以添加“ MO”,CoreData可以区分类名称和实体名称。和

@objc(Workout) 

将不会被创建,给我们这个:

class CDWorkoutMO: NSManagedObject {

 class func createWorkout(workoutInfo : Workout, in context: NSManagedObjectContext) -> CDWorkoutMO {
    let workout = CDWorkoutMO(context: context)
    workout.name = "anyName"
    return workout
}
}

like I do on my Xcode

答案 12 :(得分:0)

在AppDelegate中检查持久性容器名称。 let container = NSPersistentContainer(name:“ CoreData”)

如果您尝试获取不存在的核心数据,则可能显示为此错误。

名称应与导航菜单中的.xcdatamodeld对象完全相同。

GL:)

答案 13 :(得分:0)

对于SwiftUI,您还需要从SceneDelegate更新此方法:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    //This gets the context from AppDelegate and sets is as moc environment variable
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let contentView = ContentView().environment(\.managedObjectContext, context)
    //...
}

答案 14 :(得分:0)

我正在尝试将CoreData添加到现有项目中,并且我重命名了很多东西。我最终得到了多个.xcdatamodeld而不知道它。解决方案是删除.xcdatamodeld并生成NSManagerObject并重新创建它。

答案 15 :(得分:0)

我在CoreData堆栈中遇到类似的问题NSManagedObjectModel来自Swift代码。问题出在NSEntityDescription.managedObjectClassName属性的错误值。错过了Swift module前缀。

正确设置:

let entity = NSEntityDescription()
entity.name = PostEntity.entityName // `PostEntity`
entity.managedObjectClassName = PostEntity.entityClassName // `MyFrameworkName.PostEntity`
entity.properties = [....]

其中:entityNameentityClassName定义如下。

extension NSManagedObject {

    public static var entityName: String {
        let className = NSStringFromClass(self) // As alternative can be used `self.description()` or `String(describing: self)`
        let entityName = className.components(separatedBy: ".").last!
        return entityName
    }

    public static var entityClassName: String {
        let className = NSStringFromClass(self)
        return className
    }

}

答案 16 :(得分:0)

您需要先创建新的NSManagedObject才能使用它

let workout = NSEntityDescription.insertNewObjectForEntityForName("CDWorkout",
    inManagedObjectContext: context) as! CDWorkout

现在您可以像以前一样设置名称:workout.name = "any_name"

您可以参考CoreData Documentation了解有关CoreData的更多信息