CoreData: avertissement: impossible de charger la classe nommée

94

Je duplique une application Objective-C TV Show existante vers une nouvelle version Swift à l'aide de Xcode 6.1 et j'ai des problèmes avec CoreData.

J'ai créé un modèle de 4 entités, créé leur sous-classe NSManagedObject (dans Swift) et tous les fichiers ont les cibles d'application appropriées définies (pour 'Compile Sources').

J'obtiens toujours cette erreur chaque fois que j'essaye d'insérer une nouvelle entité:

CoreData: avertissement: impossible de charger la classe nommée «Shows» pour l'entité «Shows». Classe introuvable, utilisant à la place NSManagedObject par défaut.

Quelques remarques:

Lors de l'enregistrement dans Core Data, j'utilise la méthode de contexte parent-enfant pour autoriser le thread en arrière-plan. Je fais cela en configurant le ManagedObjectContext en utilisant:

lazy var managedObjectContext: NSManagedObjectContext? = {
  // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
  let coordinator = self.persistentStoreCoordinator
  if coordinator == nil {
    return nil
  }
  var managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
  managedObjectContext.persistentStoreCoordinator = coordinator
  return managedObjectContext
}()

et en sauvegardant les données en utilisant:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
  var context = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.PrivateQueueConcurrencyType)
  context.parentContext = self.managedObjectContext!
  ...rest of core data saving code here...
})
JimmyJammed
la source

Réponses:

177

Cet avertissement est l'une des bizarreries auxquelles nous devons faire face pendant que les détails de la mise en œuvre de Swift sont en cours de mise au point. L'avertissement se produit de manière erronée, c'est-à-dire que votre configuration peut fonctionner même si vous ne suivez pas les étapes décrites ci-dessous.

J'ai pu m'en débarrasser dans la plupart des cas en m'assurant que la classe est correctement définie dans l'éditeur de modèle . Contrairement à de nombreux autres articles SOF (y compris les réponses à cette question), la suggestion d'inclure le nom du module (comme MyApp.Shows) ne m'a pas aidé.

Assurez-vous de vérifier ces trois éléments:

1.
Version qui fonctionne jusqu'à Xcode 7 beta 3

Jusqu'à XCode7 b3

Notez que j'ai corrigé le nom de votre entité au singulier plus approprié.

Version qui fonctionne pour Swift 2.0 dans Xcode 7.1
(devrait fonctionner pour Xcode 7 beta 4 et supérieur)

Vous devez supprimer le texte "Module produit actuel" dans le module!

À partir de Xcode7 beta 3

2.
Vous devez également suivre la recommandation fréquente d'inclure

@objc(Show)

juste au-dessus de votre classe.

Remarque : si vous utilisez Xcode 7 beta 4 ou version ultérieure, cette étape est facultative.

3.
Assurez-vous également de convertir l'objet géré créé dans la classe appropriée, car la valeur par défaut serait juste NSManagedObject.

var newShow = NSEntityDescription.insertNewObjectForEntityForName("Show", 
                 inManagedObjectContext: context) as Show
Mundi
la source
3
Merci! J'ai fait les mises à jour recommandées de la convention de dénomination, et c'est le '@objc (Show)' qui semble faire l'affaire en corrigeant l'erreur 'Unable to load class ...'. Très appréciée!
JimmyJammed
Salut @Mundi. Merci beaucoup! te souviendrais-tu encore où était la source?
iamdavidlam
1
Voir par exemple cette question . Il y a suffisamment d'informations pour comprendre ce qui se passe.
Mundi
4
Chose intéressante, j'ai dû retirer @objc(MyClass)
Santa Claus
1
@Mundi, vous voudrez peut-être mettre à jour votre réponse à nouveau. Voir la mise à jour des réponses de khunshan.
Suragch
75

Mise à jour SWIFT 2 / XCODE 7:

Ce problème (voir également mon commentaire du 3 avril sur cette réponse) est résolu dans la version bêta de Swift 2 et XCode 7 par Apple. Vous n'avez donc plus besoin @objc(myEntity)de Swift comme répondu par Mundi ou en utilisant " MyAppName." avant le nom de votre classe. Cela cessera de fonctionner. Alors supprimez-les, mettez simplement le Classnom dans le fichier et sélectionnez Current Working Modulecomme module et bravo!

Sélection du module de travail actuel

Mais pour ceux qui utilisent @objc(myEntity)Swift (comme moi), vous pouvez utiliser cette autre solution à la place qui fonctionne bien.

Dans la classe correcte xcdatamodel dans. Cela devrait ressembler à ceci:

Définition de la classe

Voici. Module.Classest le modèle pour CoreData dans Swift et XCode 6. Vous aurez également besoin de la même procédure lors de l'utilisation de la classe de stratégie personnalisée dans la stratégie de modèle ou d'autres éléments CoreData. A noter: dans l'image, le nom et la classe doivent être Car et MyAppName.Car (ou quel que soit le nom de votre entité). Voici Userune faute de frappe.

Khunshan
la source
Le problème avec cette solution est que la génération automatique de classes d'entités ne fonctionnera plus correctement (elle ne générera qu'une seule classe avec le nom du module). Voir: Créer une sous-classe NSManagedObject ne se générant pas correctement .
milos le
Vous devez appliquer la solution après avoir généré des classes d'entité NSManagedObject. Probablement un bogue xcode 6.xx à supprimer.
khunshan
2
Oui, cela sera sans aucun doute résolu. Les classes générées automatiquement devraient déjà être ornées de @objc (<nom de la classe entré dans l'inspecteur d'entités>) ou, plus probablement, Apple rendra cela inutile pour commencer.
milos
2
Pour les gens qui lisent encore ceci. l'utilisation de ' MyAppName.Car ' n'a pas fonctionné pour moi, cela a fonctionné lorsque j'ai supprimé le ' MyAppName. ' partie. Donc, juste Carpour les deux domaines a fait l'affaire.
Gideon
1
vous Champ !!!! laissez person = NSEntityDescription.insertNewObject (forEntityName: "Person", into: context) as! Person
Abhimanyu Rathore
36

Lors de l'utilisation de Xcode 7 et purement Swift, je devais en fait supprimer @objc(MyClass) de ma NSManagedObjectsous - classe générée automatiquement (générée à partir de Editor> Create NSManagedObject Subclass...).

père Noël
la source
4
Wow merci d'avoir publié cette réponse. J'étais sur le point de me cogner la tête contre le mur.
Zia
Même problème ici - Soumis un bogue.
MirekE
A travaillé pour moi aussi. J'ai dû l'enlever. Bizarre.
Kent le
D'après mes expériences, cela ressemble à un faux positif.
Mundi
J'ai dû le supprimer et définir le module de produit actuel, alors seulement cela a fonctionné
Oleg Sherman
13

Dans Xcode 7 beta 2 (et je crois 1), dans la configuration du modèle, un nouvel objet géré de type Fileest défini sur le module Current Product Moduleet la classe de l'objet est affichée dans la configuration comme .File.

Module de type d'objet géré défini sur "Module de produit actuel" dans Xcode 7

Supprimer le paramètre du module pour qu'il soit vide ou supprimer le point pour que le nom de la classe dans la configuration soit juste Filesont des actions équivalentes, car chacune entraîne l'autre changement. L'enregistrement de cette configuration supprimera l'erreur décrite.

Module d'objet géré défini pour être vide dans Xcode 7

Duncan Babbage
la source
9

Dans Xcode 6.1.1, vous n'avez pas besoin d'ajouter l'attribut @objc car l'entité de base est un sous-ensemble d'une classe objc (NSManagedObject) (voir Compatibilité de type Swift . Dans CoreData, le nom Module.Class complet est requis. Attention au module nom est ce qui est défini dans Paramètres de construction -> Emballage -> Nom du module de produit. Par défaut, il est défini sur $ (PRODUCT_NAME: c99extidentifier) ​​qui sera le nom de la cible .

Jim Malak
la source
Oui! C'est la réponse moderne (xcode 6.3.2). L'utilisation du bon nom de bundle est la clé. Dans mon cas, il s'était transformé my-producten my_product, et cela a fait toute la différence pour Core Data.
SimplGy
5

Avec la version xCode 7 et Swift 2.0, vous n'avez pas besoin d'ajouter @objc (NameOfClass), modifiez simplement les paramètres de l'entité dans l'onglet "Afficher l'inspecteur de modèle de données" comme ci-dessous -

Nom - "Nom de votre entité"

Classe - "Nom de votre entité"

Module - "Module produit actuel"

entrez la description de l'image ici

Le code pour le fichier de classe d'entité sera comme (dans mon code l'entité est la famille) -

import UIKit
import CoreData

class Family: NSManagedObject {

   @NSManaged var member : AnyObject
}

Cet exemple fonctionne bien dans mon application avec xCode 7.0 + swift 2.0

Himanshu Mahajan
la source
3

N'oubliez pas de remplacer PRODUCT_MODULE_NAMEpar le nom de votre module produit.

Lorsqu'une nouvelle entité est créée, vous devez accéder à l'inspecteur de modèle de données (dernier onglet) et le remplacer PRODUCT_MODULE_NAMEpar le nom de votre module, sinon il en résultera une class not founderreur lors de la création du coordinateur de magasin persistant.

Kof
la source
2

Vous devez également utiliser (au moins avec Xcode 6.3.2) Module.Class lors de votre distribution par exemple: En supposant que votre module (c'est-à-dire le nom du produit) est Food et que votre classe est Fruit

let myEntity =  NSEntityDescription.entityForName("Fruit", inManagedObjectContext: managedContext)

let fruit = NSManagedObject(entity: myEntity!, insertIntoManagedObjectContext:managedContext) as! Food.Fruit

Résumer:

  • Inclure le nom du module lors de la définition de l'entité dans l'éditeur de modèle de données (Nom: Fruit, Classe: Food.Fruit)
  • Lors de l'accès à l'entité dans le code (ieSWIFT), lancez-la avec Module.class (par exemple Food.Fruit)
Wizkid
la source
Merci, le deuxième point est très important. J'ai dû utiliser "Module.Class" lors de la diffusion.
Zoyt
1

Changer le nom de la classe d'entité dans l'éditeur de modèle de données pour qu'il corresponde à la classe en question et l'ajout @objc(NameOfClass)au fichier de chaque NSManagedObject juste au-dessus de la déclaration de classe a résolu ce problème pour moi pendant les tests unitaires.

user3269767
la source
0

Ce qui a fonctionné pour moi (Xcode 7.4, Swift) est de changer le nom de la classe <my actual class name>.<entity name> dans l'inspecteur d'entités, dans la zone 'Classe'.

Mon initiateur de la sous-classe d'objets gérés ressemble à ceci:

    convenience init(<properties to init>) {
    let entityDescr = NSEntityDescription.entityForName("<entity class name>", inManagedObjectContext: <managed context>)
    self.init(entity: entityDescr!, insertIntoManagedObjectContext: <managed context>)}
    //init properties here
marque
la source
0

Pour Xcode 11.5: si la propriété Codegen est une définition de classe, et si vous n'obtenez pas de suggestion pour l'entité que vous avez créée dans xcdatamodel. Essayez de quitter Xcode et de rouvrir votre projet. Ça marche pour moi. Cette réponse est seulement si vous n'obtenez pas de suggestions, mais si votre fichier n'est pas généré, essayez l'une des réponses ci-dessus.

Gulshan Kumar
la source