无法找到NSManagedObject的特定子类

138

我正在开发一个使用Core Data的应用程序。当我使用以下代码创建实例时:

let entity = NSEntityDescription.entityForName("User", inManagedObjectContext: appDelegate.managedObjectContext)
let user = User(entity: entity, insertIntoManagedObjectContext: appDelegate.managedObjectContext)

我在日志中收到了一个警告:

CoreData: warning: Unable to load class named 'User' for entity 'User'.  Class not found, using default NSManagedObject instead.

我该如何修复它?

还有一个问题,如何在NSManagedObject子类中定义实例方法?

编辑:

我已经指定了实体的类,如下面的截图所示:

enter image description here


7
你是否按照 实现 Core Data 托管对象子类 文档中所述,在实体类名前加上了模块名? - Martin R
@MartinR:请看我的问题更新。 - MsrButterfly
2
类应该是“YourAppName.User”,请参阅文档(链接在我之前的评论中)。 - Martin R
@MartinR:谢谢你的帮助。它起作用了。 - MsrButterfly
最好的方法是删除那些类并重新创建。这对我有用。 - Abhishek
13个回答

221

Xcode 7更新(最终版):不再需要在类名前加上模块名称(与Xcode 6和早期Xcode 7 beta版本相同)。苹果文档实现Core Data托管对象子类已相应更新。

数据模型检查器现在为实体提供了两个字段:“类”和“模块”:

enter image description here

当您为实体创建Swift托管对象子类时,“模块”字段设置为“当前产品模块”,使用此设置在主应用程序和单元测试中都可以创建实例。托管对象子类不应标记为@objc(classname)(这是在https://dev59.com/4F8f5IYBdhLWcg3wEPEq#31288029中观察到的)。 或者,您可以清空“模块”字段(它将显示“无”),并使用@objc(classname)标记托管对象子类(这是在https://dev59.com/4F8f5IYBdhLWcg3wEPEq#31287260中观察到的)。

备注: 这篇答案最初是为Xcode 6编写的。 在各个Xcode 7 beta版本中,有一些关于这个问题的变化。由于这是一个被接受的答案,并且有很多赞和链接,我试图总结当前Xcode 7最终版本的情况。

我进行了自己的“研究”,并阅读了所有回答这个问题和类似问题CoreData: warning: Unable to load class named的答案。所以归功于他们所有人,即使我没有具体列出他们!


Xcode 6的先前答案:

实现Core Data管理对象子类所述,在模型实体检查器中的Class字段中,您必须使用您的模块名称作为前缀来为实体类名称添加前缀,例如"MyFirstSwiftApp.User"。


2
这个对我有用。问题:如果核心数据包含在框架中,由于还没有实际应用程序,如何给ManagedObject子类名加前缀? - Allan Macatingrao
9
你可以尝试Christer提出的@objc(ClassName)方法。 - Martin R
8
功能可用,但当我在实体检查器中将类名设置为"APPNAME.User"后,无法重新生成模型类:Xcode似乎对前缀感到困惑,它会生成一个名为APPNAME的文件/类。我有什么遗漏吗? - Pascal Bourque
1
如果在使用静态库中的核心数据时,在Objective-C中遇到此错误,该怎么办? - George Taskos
1
@Suragch:我现在终于更新了答案,希望现在一切都正确无误。 - Martin R
显示剩余10条评论

62

顺便提一下,我也遇到了同样的问题。解决方法是在我的类文件中添加@objc(ClassName)

示例:

@objc(Person)
class Person { }

这解决了我的问题。


1
你在Objective-C中定义了typealias (<%ProjectName%>.Person -> Person),这样它就可以工作了。 - MsrButterfly
7
如果您的项目有多个目标,并且每个目标都共享CoreData模型,那么这将特别有用。在这些情况下,无法前缀类名以使用目标标识符,因为这会使CD模型对其中一个目标有效。 - djbp
这是一种方法,直到他们在XCode中修复子类文件命名错误。 - William T.
@S'pht'Kr,四个月过去了,我们还没有解决方案。除非有人有好消息? - Dandy
这个答案已经不再正确。 - Suragch
显示剩余3条评论

31

回答这个问题的被接受答案帮助我解决了相同的问题,但是我有一个注释可以帮助其他人。如果您的项目(模块)名称中有空格,则必须用下划线替换空格。例如:

实体:MyEntity 类名:My_App_Name.MyClass


正是我在寻找的!干杯! - manosim
当我们使用AppName.ClassName设置类名时,Xcode 9会去掉点并创建一个没有点的类。因此,在Xcode 9.*中这种方法不再适用。 - yo2bh

17

请记得移除您的模块

输入图像描述


2
这解决了我的问题。 - Jason Huh

9
根据您运行的是应用程序还是测试,问题可能是应用程序正在寻找<appName>.<entityName>,而在运行测试时它正在寻找<appName>Tests.<entityName>。我目前使用的解决方法(Xcode 6.1)是不要在CoreData UI中填写Class字段,而是在代码中完成。
以下代码将检测您是否作为应用程序或测试运行,并使用正确的模块名称,并更新managedObjectClassName
lazy var managedObjectModel: NSManagedObjectModel = {
    // The managed object model for the application. This property is not optional...
    let modelURL = NSBundle.mainBundle().URLForResource("Streak", withExtension: "momd")!
    let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)!

    // Check if we are running as test or not
    let environment = NSProcessInfo.processInfo().environment as [String : AnyObject]
    let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest"

    // Create the module name
    let moduleName = (isTest) ? "StreakTests" : "Streak"

    // Create a new managed object model with updated entity class names
    var newEntities = [] as [NSEntityDescription]
    for (_, entity) in enumerate(managedObjectModel.entities) {
        let newEntity = entity.copy() as NSEntityDescription
        newEntity.managedObjectClassName = "\(moduleName).\(entity.name)"
        newEntities.append(newEntity)
    }
    let newManagedObjectModel = NSManagedObjectModel()
    newManagedObjectModel.entities = newEntities

    return newManagedObjectModel
}()

1
我尝试了你的解决方案,但是在将NSManagedObject转换为其实际类时,当进入for循环时,出现“致命错误:NSArray元素未能匹配Swift数组元素类型”的错误。实际上不是在转换本身时出错,而是在尝试进入for循环时出错。 - Rodrigo Ruiz
1
如果您的模型中存在任何形式的继承,那个例子就不起作用了。对于每个新实体,您还需要迭代子实体并使用您创建的新实体更新它们。 - Anton

8

如果您在项目名称中使用连字符,例如“My-App”,则请改用下划线,例如“My_App.MyManagedObject”。 通常情况下,查看xcdatamodeld文件的名称,并使用与该名称相同的前缀。 例如,“My_App_1.xcdatamodeld”需要前缀“ My_App_1”。


1
哇。谢谢谢谢谢谢。我很想知道在苹果文档中那个小提示在哪里 :) - nh32rg

5
这可能对遇到相同问题的人有所帮助。我在使用Swift 2和Xcode 7 beta 2时也遇到了这个问题。
在我的情况下,解决方法是在EntityName.swift文件中注释掉@objc(EntityName)

3

以上的答案很有帮助。这个快速的检查可以节省您的时间。进入 Project > Build Phases > Compile Sources,使用“-”按钮删除 xcdatamodeld 和模型文件,然后使用“+”按钮添加它们。重新构建——可能会解决问题。


3

我也遇到了同样的警告,尽管我的应用程序似乎运行良好。 问题在于当在最后一个屏幕上运行Editor > Create NSManagedObject Subclass时,我使用了默认的Group位置,没有显示或选中任何Targets,这将子类保存在位于MyApp.xcodeproj顶部的MyApp目录中。
当我改为将Group设置为MyApp子文件夹并选中MyApp目标时,警告消失了。


2

顺便提醒一下,要小心添加前缀:我的应用程序叫做“ABC-def”,而Xcode已将“-”转换为“_”。

为了安全起见,请查找finder,找到您的项目文件,并查看您的数据模型的名称(例如“ABC_def.xcdatamodeld”),并完全使用那里面写的名称!!!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接