Impossible de trouver une sous-classe spécifique de NSManagedObject

136

Je travaille sur le développement d'une application avec Core Data. Lorsque j'ai créé une instance en utilisant:

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

J'ai un avertissement dans le journal:

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

Comment pourrais-je résoudre ce problème?

Et une autre question, comment puis-je définir une méthode d'instance dans la sous-classe NSManagedObject?

Éditer:

J'ai spécifié la classe de l'entité comme dans la capture d'écran suivante:

entrez la description de l'image ici

MsrPapillon
la source
7
Avez-vous préfixé le nom de la classe des entités avec le nom du module, comme indiqué dans Implémentation des sous - classes d'objets gérés par Core Data ?
Martin R
@MartinR: Voir la mise à jour de ma question.
MsrButterfly
2
La classe doit être "YourAppName.User", voir la documentation (lien dans mon commentaire précédent).
Martin R
@MartinR: Merci pour votre aide. Ça marche.
MsrButterfly
La meilleure chose à faire est de supprimer ces classes et de les recréer. Cela a fonctionné pour moi
Abhishek

Réponses:

220

Mise à jour pour Xcode 7 (finale): il n'est plus nécessaire de préparer le nom du module dans la classe (comme dans Xcode 6 et les premières versions bêta de Xcode 7). La documentation Apple Implémentation des sous-classes d'objets gérés par Core Data a été mise à jour en conséquence.

L'inspecteur de modèle de données comporte désormais deux champs «Classe» et «Module» pour une entité:

entrez la description de l'image ici

Lorsque vous créez une sous-classe d'objets gérés Swift pour l'entité, le champ «Module» est défini sur «Module de produit actuel» et, avec ce paramètre, la création d'instances fonctionne à la fois dans l'application principale et dans les tests unitaires. La sous-classe d'objets gérés ne doit pas être marquée @objc(classname)(ceci a été observé dans https://stackoverflow.com/a/31288029/1187415 ).

Vous pouvez également vider le champ «Module» (il affichera «Aucun») et marquer les sous-classes d'objets gérés avec @objc(classname)(cela a été observé dans https://stackoverflow.com/a/31287260/1187415 ).


Remarque: Cette réponse a été écrite à l'origine pour Xcode 6. Il y a eu quelques changements dans les différentes versions bêta de Xcode 7 par rapport à ce problème. Puisqu'il s'agit d'une réponse acceptée avec de nombreuses votes favorables et des liens vers elle, j'ai essayé de résumer la situation pour la version finale actuelle de Xcode 7.

J'ai fait mes propres "recherches" et lu toutes les réponses à la fois à cette question et à la question similaire CoreData: avertissement: Impossible de charger la classe nommée . L'attribution va donc à tous, même si je ne les énumère pas spécifiquement!


Réponse précédente pour Xcode 6 :

Comme indiqué dans Implémentation des sous - classes d'objets gérés par Core Data , vous devez préfixer le nom de la classe des entités dans le champ Classe de l'inspecteur d'entités de modèle avec le nom de votre module, par exemple "MyFirstSwiftApp.User".

Martin R
la source
2
Celui-ci fonctionne pour moi. Question: Que faire si les données de base sont incluses dans un framework, comment préfixer le nom de la sous-classe ManagedObject puisqu'il n'y a pas encore d'application réelle?
Allan Macatingrao
9
@Allan: Vous pouvez essayer la @objc(ClassName)méthode suggérée dans la réponse de Christer.
Martin R
8
Cela fonctionne, mais une fois que j'ai défini le nom de la classe sur "APPNAME.User" dans l'inspecteur d'entités, je suis incapable de régénérer les classes de modèle: Xcode semble être confondu par le préfixe, et il génère un fichier / classe avec le nom NOM DE L'APPLICATION. Est-ce que je manque quelque chose?
Pascal Bourque
1
Que faire si vous obtenez cette erreur dans Objective-C lors de l'utilisation de données de base dans une bibliothèque statique?
George Taskos
1
@Suragch: J'ai enfin mis à jour la réponse, j'espère que tout est correct maintenant.
Martin R
62

Juste comme note d'accompagnement. J'ai eu le même problème. Et tout ce que j'avais à faire était d'ajouter @objc(ClassName)dans mon dossier de classe.

Exemple:

@objc(Person)
class Person { }

Et cela a résolu mon problème.

Christer
la source
1
Vous avez défini les typealias (<% ProjectName%>. Person -> Person) dans Objective-C de cette manière, donc cela fonctionne.
MsrButterfly
On dirait qu'Apple a oublié de le convertir complètement en swift .. je ne sais pas pourquoi mais cela m'a
corrigé
7
Ceci est particulièrement utile si vous avez un projet avec plusieurs cibles, où chaque cible partage le modèle CoreData. Dans ces cas, il n'est pas possible de préfixer le nom de la classe avec celui de l'identifiant cible car cela rend le modèle de CD utile à une seule des cibles.
djbp
@djbp Et "pourquoi pas?" J'aimerais savoir. J'aime le concept d'espacement des noms, mais cela m'a donné envie de jeter mon MacBook par la fenêtre (j'ai une application avec une extension et j'ai rencontré ce problème lors de l'exécution de l'extension). Il doit y avoir une "bonne" façon de faire cela avec les espaces de noms, je n'arrive pas à comprendre.
S'pht'Kr
Ouais, cela a fonctionné pour moi lorsque je travaille avec des modèles de données partagées dans un espace de travail
naz
31

La réponse acceptée à cette question m'a aidé à résoudre le même problème, mais j'avais une mise en garde qui, à mon avis, serait utile pour les autres. Si le nom de votre projet (module) contient un espace, vous devez remplacer l'espace par un trait de soulignement. Par exemple:

Entité: MyEntity Classe: My_App_Name.MyClass

Mannix
la source
Exactement ce que je cherchais! À votre santé!
manosim
Lorsque nous définissons le nom de la classe avec AppName.ClassName, Xcode 9 supprime le point et crée une classe sans point. Ce n'est donc plus dans Xcode 9. *.
yo2bh
17

N'oubliez pas de supprimer votre module :

entrez la description de l'image ici

Bartłomiej Semańczyk
la source
1
Cela a résolu mon problème!
simme
2
Cela a résolu mon problème.
Jason Huh le
9

Selon que vous exécutez en tant qu'application vs tests, le problème peut être que l'application recherche <appName>.<entityName>et lorsqu'elle s'exécute en tant que test, elle ressemble <appName>Tests.<entityName>. La solution que j'utilise actuellement (Xcode 6.1) est de NE PAS remplir le Classchamp dans l'interface utilisateur CoreData, et de le faire dans le code à la place.

Ce code détectera si vous exécutez en tant qu'application vs tests, utilisez le bon nom de module et mettez à jour le fichier 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
}()
Ludovic Landry
la source
1
J'ai essayé votre solution mais j'obtiens une "erreur fatale: l'élément NSArray n'a pas réussi à correspondre au type d'élément Swift Array" lors de la conversion de NSManagedObject dans sa classe réelle. En fait, pas lors du casting, mais en essayant d'entrer dans une boucle for.
Rodrigo Ruiz
1
Cet exemple ne fonctionne pas si vous avez une sorte d'héritage dans votre modèle. Pour chaque nouvelle entité, vous devez également parcourir les sous-entités et les mettre à jour avec les nouvelles entités que vous avez créées.
Anton
8

Si vous utilisez un trait d'union dans le nom de votre projet comme "My-App", utilisez un trait de soulignement au lieu du trait d'union comme "My_App.MyManagedObject". En général, regardez le nom du fichier xcdatamodeld et utilisez le même préfixe que dans ce nom. Ie "My_App_1.xcdatamodeld" nécessite le préfixe "My_App_1"

Rien
la source
1
sensationnel. Merci merci merci. Je serais intéressé de savoir où se trouve cette petite pépite dans la documentation Apple :)
NH32RG
5

Cela peut aider ceux qui rencontrent le même problème. J'étais, avec Swift 2 et Xcode 7 beta 2.

La solution dans mon cas était de commenter @objc(EntityName)dans EntityName.swift.

enreas
la source
3

J'ai eu le même avertissement, même si mon application semblait fonctionner correctement. Le problème était que lors de l'exécution de Editor> Create NSManagedObject Subclass sur le dernier écran, j'ai utilisé l'emplacement du groupe par défaut, sans aucune cible affichée ni cochée, ce qui a enregistré la sous-classe dans le répertoire MyApp supérieur où MyApp.xcodeproj était situé.
L'avertissement a disparu lorsque j'ai plutôt changé le groupe pour qu'il se trouve dans le sous-dossier MyApp et vérifié la cible MyApp.

Daniel Ford
la source
2

Les réponses ci-dessus ont été utiles. Cette vérification rapide de la cohérence peut vous faire gagner du temps. Allez dans Projet> Phases de construction> Compiler les sources et supprimez votre xcdatamodeld et vos fichiers de modèle avec le bouton "-", puis ajoutez-les tout de suite avec le bouton "+". Reconstruire - cela peut s'en occuper.

trevorgrayson
la source
2

Au fait, soyez prudent avec ce que vous ajoutez comme préfixe: mon application s'appelle "ABC-def" et Xcode a converti le "-" en "_".

Pour être sûr, regardez dans le Finder, trouvez vos fichiers de projet et voyez ce qu'il dit pour votre modèle de données (par exemple "ABC_def.xcdatamodeld") et utilisez ce qui y est écrit EXACTEMENT !!!

Mike
la source
1

Les réponses ci-dessus m'ont aidé à résoudre différents problèmes liés à Objective-C (peut-être que cela aidera quelqu'un):

Si vous avez refactoré les noms d'entités, n'oubliez pas de modifier également "Classe" dans "Panneau Utilitaires".

Vive
la source
0

Les réponses ci-dessus m'ont aidé, mais cela peut aider quelqu'un. Si comme moi vous les avez fait et que vous rencontrez toujours un problème, n'oubliez pas de simplement «nettoyer votre projet». Pour XCode8, Produit> Nettoyer. Puis exécutez à nouveau.

Olaolu Akinsete
la source
0

Dans Xcode 7, les noms d'entité et de classe peuvent être identiques, mais Codegen doit être une définition de classe. Dans ce cas, il n'y aura pas d'avertissement, etc. entrez la description de l'image ici

dcaric
la source