No se puede encontrar una subclase específica de NSManagedObject


136

Estoy trabajando en el desarrollo de una aplicación con Core Data. Cuando creé una instancia usando:

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

Recibí una advertencia en el registro:

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

¿Cómo podría arreglarlo?

Y otra pregunta, ¿cómo puedo definir un método de instancia en la subclase NSManagedObject?

Editar:

He especificado la clase de la entidad como en la siguiente captura de pantalla:

ingrese la descripción de la imagen aquí


77
¿Ha prefijado el nombre de la clase de entidades con el nombre del módulo, como se documenta en Implementación de subclases de objetos gestionados de datos básicos ?
Martin R

@ MartininR: Vea la actualización de mi pregunta.
MsrButterfly

2
La clase debe ser "YourAppName.User", consulte la documentación (enlace en mi comentario anterior).
Martin R

@ Martinin: Gracias por tu ayuda. Funciona.
MsrButterfly

Lo mejor es eliminar esas clases y volver a crearlas. Esto funcionó para mí
Abhishek

Respuestas:


220

Actualización para Xcode 7 (final): ya no es necesario anteponer el nombre del módulo a la clase (como en Xcode 6 y las primeras versiones beta de Xcode 7). La documentación de Apple que implementa las subclases de objetos gestionados de datos básicos se ha actualizado en consecuencia.

El inspector del modelo de datos tiene ahora dos campos "Clase" y "Módulo" para una entidad:

ingrese la descripción de la imagen aquí

Cuando crea una subclase de objeto gestionado Swift para la entidad, el campo "Módulo" se establece en "Módulo de producto actual", y con esta configuración, la creación de instancias funciona tanto en la aplicación principal como en las pruebas unitarias. La subclase de objeto gestionado no debe marcarse con @objc(classname)(esto se observó en https://stackoverflow.com/a/31288029/1187415 ).

Alternativamente, puede vaciar el campo "Módulo" (mostrará "Ninguno") y marcar las subclases de objetos administrados con @objc(classname)(esto se observó en https://stackoverflow.com/a/31287260/1187415 ).


Observación: Esta respuesta se escribió originalmente para Xcode 6. Hubo algunos cambios en las diversas versiones beta de Xcode 7 con respecto a este problema. Como es una respuesta aceptada con muchos votos a favor y enlaces, he intentado resumir la situación para la versión final actual de Xcode 7.

Hice mi propia "investigación" y leí todas las respuestas tanto a esta pregunta como a la pregunta similar CoreData: advertencia: No se puede cargar la clase nombrada . ¡Entonces la atribución va a todos ellos, incluso si no los enumero específicamente!


Respuesta anterior para Xcode 6 :

Como se documenta en Implementación de subclases de objetos gestionados de datos básicos , debe prefijar el nombre de la clase de entidades en el campo Clase en el inspector de entidades modelo con el nombre de su módulo, por ejemplo "MyFirstSwiftApp.User".


2
Este me está funcionando. Pregunta: ¿Qué sucede si los datos principales se incluyen en un marco, cómo prefijar el nombre de la subclase ManagedObject ya que aún no hay una aplicación real?
Allan Macatingrao

9
@Allan: Podrías probar el @objc(ClassName)método sugerido en la respuesta de Christer.
Martin R

8
Funciona, pero una vez que establecí el nombre de la clase en "APPNAME.User" en el inspector de entidades, no puedo regenerar las clases de modelo: Xcode parece estar confundido por el prefijo y genera un archivo / clase con el nombre NOMBRE DE LA APLICACIÓN. ¿Me estoy perdiendo de algo?
Pascal Bourque

1
¿Qué sucede si obtiene este error en Objective-C cuando usa datos centrales en una biblioteca estática?
George Taskos

1
@Suragch: ahora finalmente he actualizado la respuesta, espero que todo esté correcto ahora.
Martin R

62

Solo como una nota al margen. Tuve el mismo problema. Y todo lo que tenía que hacer era agregar @objc(ClassName)mi archivo de clase.

Ejemplo:

@objc(Person)
class Person { }

Y eso resolvió mi problema.


1
Definió typealias (<% ProjectName%>. Person -> Person) en Objective-C de esa manera, por lo que funciona.
MsrButterfly

Parece que Apple olvidó convertirlo completamente a la velocidad ... no sé por qué, pero esto me lo arregló con bastante suavidad
Jiří Zahálka

77
Esto es particularmente útil si tiene un proyecto con múltiples objetivos, donde cada objetivo comparte el modelo CoreData. En estos casos, no es posible prefijar el nombre de la clase con el del identificador de destino, ya que eso hace que el modelo de CD sea útil solo para uno de los objetivos.
djbp

@djbp Y "¿por qué no?" Me gustaría saber. Me gusta el concepto de espacio de nombres, pero esto me hizo querer tirar mi MacBook por la ventana (tengo una aplicación con una extensión, y me encontré con este problema al ejecutar la extensión). Tiene que haber una forma "correcta" de hacer esto con espacios de nombres, simplemente no puedo entenderlo.
S'pht'Kr

Sí, esto funcionó para mí cuando trabajaba con modelos de datos compartidos en un espacio de trabajo
naz

31

La respuesta aceptada a esta pregunta me ayudó a resolver el mismo problema, pero tenía una advertencia que pensé que sería útil para los demás. Si el nombre de su proyecto (módulo) tiene un espacio, debe reemplazar el espacio con un guión bajo. Por ejemplo:

Entidad: MyEntity Clase: My_App_Name.MyClass


¡Exactamente lo que estaba buscando! ¡Salud!
manosim

Cuando establecemos el nombre de la clase con AppName.ClassName, Xcode 9 elimina el punto y crea una clase sin punto. Entonces esto ya no está en Xcode 9. *.
yo2bh


9

Dependiendo de si está ejecutando App vs Tests, el problema puede ser que la aplicación esté buscando <appName>.<entityName>y cuando se esté ejecutando como prueba <appName>Tests.<entityName>. La solución que uso en este momento (Xcode 6.1) es NO llenar el Classcampo en la interfaz de usuario CoreData, y hacerlo en el código.

Este código detectará si está ejecutando App vs Tests y usa el nombre del módulo correcto y actualiza el 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
Intenté su solución, pero obtengo un "error fatal: el elemento NSArray no pudo coincidir con el tipo de elemento Swift Array" al convertir el NSManagedObject en su clase real. En realidad, no cuando se lanza solo, sino al intentar entrar en un bucle for.
Rodrigo Ruiz

1
Ese ejemplo no funciona si tiene algún tipo de herencia en su modelo. Para cada nueva entidad, también debe iterar sobre subentidades y actualizarlas con las nuevas entidades que creó.
Anton

8

Si está usando un guión en el nombre de su proyecto como "Mi aplicación", use un guión bajo en lugar del guión como "My_App.MyManagedObject". En general, mire el nombre del archivo xcdatamodeld y use el mismo prefijo que en ese nombre. Es decir, "My_App_1.xcdatamodeld" requiere el prefijo "My_App_1"


1
Guau. Gracias, gracias, gracias. Me interesaría saber en qué parte de los documentos de Apple está esa pequeña pepita :)
nh32rg

5

Esto puede ayudar a quienes experimentan el mismo problema. Lo estaba, con Swift 2 y Xcode 7 beta 2.

La solución en mi caso fue comentar @objc(EntityName)en EntityName.swift.


3

Tuve la misma advertencia, aunque mi aplicación parecía funcionar bien. El problema fue que cuando ejecuté Editor> Crear subclase de NSManagedObject en la última pantalla, usé la ubicación predeterminada del grupo, sin mostrar ni marcar objetivos, lo que guardó la subclase en el directorio superior de MyApp donde se encontraba MyApp.xcodeproj.
La advertencia desapareció cuando en cambio cambié el Grupo para que estuviera en la subcarpeta MyApp y verifiqué el objetivo MyApp.


2

Las respuestas anteriores fueron útiles. Este rápido control de cordura puede ahorrarle algo de tiempo. Vaya a Proyecto> Fases de compilación> Compilar fuentes y elimine su xcdatamodeld y sus archivos de modelo con el botón "-", y luego vuelva a agregarlos con el botón "+". Reconstruir: eso puede solucionarlo.


2

Por cierto, tenga cuidado con lo que agrega como prefijo: mi aplicación se llama "ABC-def" y Xcode ha convertido el "-" en un "_".

Para estar seguro, busque en el buscador, encuentre los archivos de su proyecto y vea lo que dice para su modelo de datos (por ejemplo, "ABC_def.xcdatamodeld") y use lo que está escrito EXACTAMENTE.


1

Las respuestas anteriores me ayudaron a resolver diferentes problemas relacionados con Objective-C (tal vez ayudará a alguien):

Si refactorizó los nombres de las entidades, no olvide cambiar también la "Clase" en el "Panel de utilidades".


0

Las respuestas anteriores me ayudaron, pero esto puede ayudar a alguien. Si, como yo, los hizo y todavía tiene un problema, recuerde simplemente "limpiar su proyecto". Para XCode8, Producto> Limpiar. Luego corre de nuevo.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.