Eine bestimmte Unterklasse von NSManagedObject konnte nicht gefunden werden

136

Ich arbeite an der Entwicklung einer App mit Core Data. Als ich eine Instanz erstellt habe mit:

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

Ich habe eine Warnung im Protokoll erhalten:

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

Wie könnte ich das beheben?

Und noch eine Frage: Wie kann ich eine Instanzmethode in der NSManagedObject-Unterklasse definieren?

Bearbeiten:

Ich habe die Klasse der Entität wie im folgenden Screenshot angegeben:

Geben Sie hier die Bildbeschreibung ein

MsrButterfly
quelle
7
Haben Sie dem Namen der Entitätsklasse den Modulnamen vorangestellt, wie in Implementieren von Unterklassen für verwaltete Kerndatenobjekte dokumentiert ?
Martin R
@ MartinR: Siehe das Update meiner Frage.
MsrButterfly
2
Die Klasse sollte "YourAppName.User" sein, siehe Dokumentation (Link in meinem vorherigen Kommentar).
Martin R
@ MartinR: Danke für deine Hilfe. Es klappt.
MsrButterfly
Am besten löschen Sie diese Klassen und erstellen sie neu. Das hat bei mir funktioniert
Abhishek

Antworten:

220

Update für Xcode 7 (endgültig): Das Voranstellen des Modulnamens für die Klasse (wie in Xcode 6 und frühen Beta-Versionen von Xcode 7) ist nicht mehr erforderlich. Die Apple-Dokumentation zum Implementieren von Core Data Managed Object-Unterklassen wurde entsprechend aktualisiert.

Der Datenmodellinspektor verfügt jetzt über zwei Felder "Klasse" und "Modul" für eine Entität:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie eine Swift-Unterklasse für verwaltete Objekte für die Entität erstellen, wird das Feld "Modul" auf "Aktuelles Produktmodul" gesetzt. Mit dieser Einstellung funktioniert das Erstellen von Instanzen sowohl in der Hauptanwendung als auch in Komponententests. Die Unterklasse für verwaltete Objekte darf nicht mit markiert sein @objc(classname)(dies wurde unter https://stackoverflow.com/a/31288029/1187415 beobachtet ).

Alternativ können Sie das Feld "Modul" leeren (es wird "Keine" angezeigt) und die Unterklassen für verwaltete Objekte mit markieren @objc(classname)(dies wurde unter https://stackoverflow.com/a/31287260/1187415 beobachtet ).


Anmerkung: Diese Antwort wurde ursprünglich für Xcode 6 geschrieben. In Bezug auf dieses Problem gab es einige Änderungen in den verschiedenen Betaversionen von Xcode 7. Da es sich um eine akzeptierte Antwort mit vielen Upvotes und Links handelt, habe ich versucht, die Situation für die aktuelle Xcode 7-Endversion zusammenzufassen.

Ich habe sowohl meine eigenen "Nachforschungen" angestellt als auch alle Antworten auf diese und die ähnliche Frage gelesen. CoreData: Warnung: Klasse mit Namen kann nicht geladen werden . Die Zuschreibung geht also an alle, auch wenn ich sie nicht speziell aufführe!


Vorherige Antwort für Xcode 6 :

Wie unter Implementieren von Core Data Managed Object-Unterklassen dokumentiert , müssen Sie dem Namen der Entitätsklasse im Feld Klasse im Modellentitätsinspektor den Namen Ihres Moduls voranstellen, z. B. "MyFirstSwiftApp.User".

Martin R.
quelle
2
Dieser arbeitet für mich. Frage: Was passiert, wenn die Kerndaten in einem Framework enthalten sind, wie der Name der ManagedObject-Unterklasse vorangestellt wird, da noch keine tatsächliche App vorhanden ist?
Allan Macatingrao
9
@Allan: Sie könnten die @objc(ClassName)in Christers Antwort vorgeschlagene Methode ausprobieren .
Martin R
8
Es funktioniert, aber sobald ich den Klassennamen im Entitätsinspektor auf "APPNAME.User" gesetzt habe, kann ich keine Modellklassen neu generieren: Xcode scheint durch das Präfix verwirrt zu sein und generiert eine Datei / Klasse mit dem Namen APP NAME. Vermisse ich etwas
Pascal Bourque
1
Was passiert, wenn Sie diesen Fehler in Objective-C erhalten, wenn Sie Kerndaten in einer statischen Bibliothek verwenden?
George Taskos
1
@Suragch: Ich habe jetzt endlich die Antwort aktualisiert, ich hoffe, dass jetzt alles richtig ist.
Martin R
62

Nur als Randnotiz. Ich hatte das gleiche Problem. Und alles was ich tun musste war hinzuzufügen@objc(ClassName) in meine Klassendatei einzufügen.

Beispiel:

@objc(Person)
class Person { }

Und das hat mein Problem gelöst.

Christer
quelle
1
Auf diese Weise haben Sie in Objective-C Typealien (<% ProjectName%>. Person -> Person) definiert, damit dies funktioniert.
MsrButterfly
Scheint, als hätte Apple vergessen, es vollständig auf den schnellen umzustellen. Ich weiß nicht warum, aber das hat es für mich ziemlich sanft behoben
Jiří Zahálka
7
Dies ist besonders nützlich, wenn Sie ein Projekt mit mehreren Zielen haben, bei dem jedes Ziel das CoreData-Modell gemeinsam nutzt. In diesen Fällen ist es nicht möglich, dem Klassennamen den Namen der Zielkennung voranzustellen, da das CD-Modell nur für eines der Ziele nützlich ist.
DJBP
@djbp Und "warum nicht?" Ich würde gerne wissen. Ich mag das Konzept des Namespaces, aber das hat mich dazu gebracht, mein MacBook aus dem Fenster zu werfen (ich habe eine App mit einer Erweiterung und bin beim Ausführen der Erweiterung auf dieses Problem gestoßen). Es muss einen "richtigen" Weg geben, dies mit Namespaces zu tun, ich kann es einfach nicht herausfinden.
S'pht'Kr
Ja, das hat bei mir funktioniert, als ich mit gemeinsam genutzten Datenmodellen in einem Arbeitsbereich gearbeitet habe
am
31

Die akzeptierte Antwort auf diese Frage half mir, das gleiche Problem zu lösen, aber ich hatte eine Einschränkung, von der ich dachte, dass sie für andere hilfreich sein würde. Wenn Ihr Projektname (Modulname) ein Leerzeichen enthält, müssen Sie das Leerzeichen durch einen Unterstrich ersetzen. Beispielsweise:

Entität: MyEntity Klasse: My_App_Name.MyClass

Mannix
quelle
Genau das habe ich gesucht! Prost!
Manosim
Wenn wir den Klassennamen mit AppName.ClassName festlegen, entfernt Xcode 9 den Punkt und erstellt eine Klasse ohne Punkt. Das ist also nicht mehr in Xcode 9. *.
yo2bh
17

Denken Sie daran, Ihr Modul zu entfernen :

Geben Sie hier die Bildbeschreibung ein

Bartłomiej Semańczyk
quelle
1
Dies hat mein Problem behoben!
Simme
2
Dies hat mein Problem behoben.
Jason Huh
9

Abhängig davon, ob Sie als App gegen Tests ausgeführt werden, kann das Problem darin bestehen, dass die App sucht <appName>.<entityName>und wenn sie als Test ausgeführt wird, wie sie aussieht <appName>Tests.<entityName>. Die Lösung, die ich derzeit verwende (Xcode 6.1), besteht darin, die NICHT zu füllenClass derzeit verwende Feld in der CoreData-Benutzeroberfläche und es stattdessen im Code auszuführen.

Dieser Code erkennt, ob Sie als App vs Tests ausgeführt werden, verwendet den richtigen Modulnamen und aktualisiert das 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
quelle
1
Ich habe Ihre Lösung ausprobiert, erhalte jedoch die Meldung "Schwerwiegender Fehler: NSArray-Element konnte nicht mit dem Swift Array-Elementtyp übereinstimmen", wenn das NSManagedObject in seine tatsächliche Klasse umgewandelt wurde. Eigentlich nicht beim Casting selbst, sondern beim Versuch, in eine for-Schleife zu gehen.
Rodrigo Ruiz
1
Dieses Beispiel funktioniert nicht, wenn Ihr Modell eine Vererbung aufweist. Für jede neue Entität müssen Sie auch über Unterentitäten iterieren und diese mit den neu erstellten Entitäten aktualisieren.
Anton
8

Wenn Sie in Ihrem Projektnamen einen Bindestrich wie "My-App" verwenden, verwenden Sie anstelle des Bindestrichs wie "My_App.MyManagedObject" einen Unterstrich. Überprüfen Sie im Allgemeinen den Namen der xcdatamodeld-Datei und verwenden Sie dasselbe Präfix wie in diesem Namen. Dh "My_App_1.xcdatamodeld" erfordert das Präfix "My_App_1"

Rien
quelle
1
Beeindruckend. Danke danke danke. Ich würde gerne wissen, wo in den Apple-Dokumenten dieses kleine Nugget ist :)
nh32rg
5

Dies kann denjenigen helfen, bei denen das gleiche Problem auftritt. Ich war mit Swift 2 und Xcode 7 Beta 2.

Die Lösung in meinem Fall war auszukommen @objc(EntityName)in EntityName.swift.

enreas
quelle
3

Ich hatte die gleiche Warnung, obwohl meine App gut zu laufen schien. Das Problem war, dass ich beim Ausführen von Editor> NSManagedObject-Unterklasse auf dem letzten Bildschirm den Standardspeicherort der Gruppe ohne angezeigte oder aktivierte Ziele verwendet habe, wodurch die Unterklasse im obersten MyApp-Verzeichnis gespeichert wurde, in dem sich MyApp.xcodeproj befand.
Die Warnung verschwand, als ich stattdessen die Gruppe in den MyApp-Unterordner änderte und das MyApp-Ziel überprüfte.

Daniel Ford
quelle
2

Die obigen Antworten waren hilfreich. Diese schnelle Überprüfung der geistigen Gesundheit kann Ihnen Zeit sparen. Gehen Sie zu Projekt> Phasen erstellen> Quellen kompilieren und entfernen Sie Ihr xcdatamodeld und Ihre Modelldateien mit der Schaltfläche "-". Fügen Sie sie dann mit der Schaltfläche "+" wieder hinzu. Wiederaufbau - das kann sich darum kümmern.

Trevorgrayson
quelle
2

Übrigens, seien Sie vorsichtig, was Sie als Präfix hinzufügen: Meine App heißt "ABC-def" und Xcode hat das "-" in ein "_" umgewandelt.

Um sicher zu gehen, schauen Sie in den Finder, suchen Sie Ihre Projektdateien und sehen Sie, was darin für Ihr Datenmodell steht (zum Beispiel "ABC_def.xcdatamodeld") und verwenden Sie das, was dort genau geschrieben steht !!!

Mike
quelle
1

Die obigen Antworten haben mir geholfen, verschiedene Probleme im Zusammenhang mit Objective-C zu lösen (vielleicht hilft es jemandem):

Wenn Sie Entitätsnamen überarbeitet haben, vergessen Sie nicht, "Klasse" auch im "Dienstprogrammfenster" zu ändern.

Vive
quelle
0

Die obigen Antworten haben mir geholfen, aber das kann jemandem helfen. Wenn Sie sie wie ich gemacht haben und immer noch ein Problem haben, denken Sie daran, einfach Ihr Projekt zu bereinigen. Für XCode8 Produkt> Reinigen. Dann wieder laufen.

Olaolu Akinsete
quelle