Impossibile trovare la sottoclasse specifica di NSManagedObject


136

Sto lavorando allo sviluppo di un'app con Core Data. Quando ho creato un'istanza usando:

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

Ho ricevuto un avviso nel registro:

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

Come potrei ripararlo?

E un'altra domanda, come posso definire un metodo di istanza nella sottoclasse NSManagedObject?

Modificare:

Ho specificato la classe dell'entità come nella seguente schermata:

inserisci qui la descrizione dell'immagine


7
Hai aggiunto il prefisso al nome della classe entità con il nome del modulo, come documentato in Implementazione di sottoclassi di oggetti gestiti con dati core ?
Martin R

@MartinR: vedi l'aggiornamento della mia domanda.
MsrButterfly,

2
La classe dovrebbe essere "YourAppName.User", vedere la documentazione (collegamento nel mio commento precedente).
Martin R

@MartinR: grazie per l'aiuto. Funziona.
MsrButterfly,

La cosa migliore è eliminare quelle classi e ricrearle. Questo ha funzionato per me
Abhishek,

Risposte:


220

Aggiornamento per Xcode 7 (finale): non è più necessario preparare il nome del modulo per la classe (come in Xcode 6 e nelle prime versioni beta di Xcode 7). La documentazione Apple relativa all'implementazione delle sottoclassi degli oggetti gestiti dati principali è stata aggiornata di conseguenza.

L'ispettore Modello di dati ha ora due campi "Classe" e "Modulo" per un'entità:

inserisci qui la descrizione dell'immagine

Quando si crea una sottoclasse di oggetti gestiti Swift per l'entità, il campo "Modulo" è impostato su "Modulo prodotto corrente" e con questa impostazione la creazione di istanze funziona sia nell'applicazione principale che nei test unitari. La sottoclasse degli oggetti gestiti non deve essere contrassegnata con @objc(classname)(questo è stato osservato in https://stackoverflow.com/a/31288029/1187415 ).

In alternativa, è possibile svuotare il campo "Modulo" (mostrerà "Nessuno") e contrassegnare le sottoclassi degli oggetti gestiti con @objc(classname)(questo è stato osservato in https://stackoverflow.com/a/31287260/1187415 ).


Nota: questa risposta è stata originariamente scritta per Xcode 6. Vi sono state alcune modifiche nelle varie versioni beta di Xcode 7 rispetto a questo problema. Dal momento che è una risposta accettata con molti voti e collegamenti, ho cercato di riassumere la situazione per l'attuale versione finale di Xcode 7.

Ho fatto entrambe le mie "ricerche" e ho letto tutte le risposte sia a questa domanda che alla domanda simile CoreData: avviso: impossibile caricare la classe denominata . Quindi l'attribuzione va a tutti loro, anche se non li elenco specificamente!


Risposta precedente per Xcode 6 :

Come documentato in Implementazione di sottoclassi di oggetti gestiti dati principali , è necessario aggiungere il nome della classe entità nel campo Classe nella finestra di ispezione entità modello con il nome del modulo, ad esempio "MyFirstSwiftApp.User".


2
Questo funziona per me. Domanda: cosa succede se i dati principali sono inclusi in un framework, come aggiungere il prefisso al nome della sottoclasse ManagedObject poiché non esiste ancora un'app reale?
Allan Macatingrao,

9
@Allan: potresti provare il @objc(ClassName)metodo suggerito nella risposta di Christer.
Martin R,

8
Funziona, ma una volta impostato il nome della classe su "APPNAME.User" nella finestra di ispezione entità, non sono in grado di rigenerare le classi del modello: Xcode sembra essere confuso dal prefisso e genera un file / classe con il nome NOME DELL'APPLICAZIONE. Mi sto perdendo qualcosa?
Pascal Bourque,

1
Cosa succede se si ottiene questo errore in Objective-C quando si utilizzano i dati di base in una libreria statica?
George Taskos,

1
@Suragch: ora ho finalmente aggiornato la risposta, spero che ora sia tutto corretto.
Martin R

62

Proprio come una nota a margine. ho avuto lo stesso problema. E tutto quello che dovevo fare era aggiungere il @objc(ClassName)mio file di classe.

Esempio:

@objc(Person)
class Person { }

E questo ha risolto il mio problema.


1
In questo modo hai definito typealias (<% ProjectName%>. Person -> Person) in Objective-C, quindi funziona.
MsrButterfly,

Sembra che Apple abbia dimenticato di convertirlo completamente in rapido ... non so perché ma questo mi ha risolto abbastanza delicatamente per me
Jiří Zahálka

7
Ciò è particolarmente utile se si dispone di un progetto con più target, in cui ciascun target condivide il modello CoreData. In questi casi, non è possibile anteporre il nome della classe a quello dell'identificatore di destinazione poiché ciò rende il modello di CD utile solo a una delle destinazioni.
DJJP

@djbp E "perché no?" Mi piacerebbe saperlo Mi piace il concetto di spazio dei nomi, ma questo mi ha fatto venir voglia di buttare il mio MacBook fuori dalla finestra (ho un'app con un'estensione e ho riscontrato questo problema quando eseguo l'estensione). Ci deve essere un modo "giusto" per farlo con gli spazi dei nomi, non riesco proprio a capirlo.
S'pht'Kr

Sì, questo ha funzionato per me quando ho lavorato con modelli di dati condivisi in un'area di lavoro
naz

31

La risposta accettata a questa domanda mi ha aiutato a risolvere lo stesso problema, ma avevo un avvertimento che pensavo sarebbe stato utile per gli altri. Se il nome del tuo progetto (modulo) contiene uno spazio, devi sostituire lo spazio con un carattere di sottolineatura. Per esempio:

Entità: MyEntity Class: My_App_Name.MyClass


Proprio quello che stavo cercando! Saluti!
Manosim,

Quando impostiamo il nome della classe con AppName.ClassName, Xcode 9 rimuove il punto e crea una classe senza un punto. Quindi questo non è più in Xcode 9. *.
yo2bh


9

A seconda che si stia eseguendo come App vs Test, il problema può essere che l'app sta cercando <appName>.<entityName>e quando è in esecuzione come test <appName>Tests.<entityName>. La soluzione che uso in questo momento (Xcode 6.1) è NON compilare il Classcampo nell'interfaccia utente di CoreData e farlo invece in codice.

Questo codice rileverà se stai eseguendo come App vs Test e usa il nome del modulo corretto e aggiorna il 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
Ho provato la tua soluzione ma sto ottenendo "errore fatale: l'elemento NSArray non è riuscito a corrispondere al tipo di elemento Swift Array" durante il cast di NSManagedObject nella sua classe effettiva. In realtà non quando si lancia se stesso, ma quando si tenta di entrare in un ciclo for.
Rodrigo Ruiz,

1
Quell'esempio non funziona se hai qualche tipo di eredità nel tuo modello. Per ogni nuova entità devi anche scorrere i sotto-siti e aggiornarli con le nuove entità che hai creato.
Anton

8

Se stai usando un trattino nel nome del tuo progetto come "My-App", usa un trattino basso invece del trattino come "My_App.MyManagedObject". In generale, guarda il nome del file xcdatamodeld e usa lo stesso prefisso di quel nome. Vale a dire "My_App_1.xcdatamodeld" richiede il prefisso "My_App_1"


1
Wow. Grazie, grazie, grazie. Sarei interessato a sapere dove è nei documenti Apple quel piccolo pepita :)
nh32rg

5

Questo può aiutare chi ha lo stesso problema. Lo ero, con Swift 2 e Xcode 7 beta 2.

La soluzione nel mio caso è stato quello di commentare @objc(EntityName)in EntityName.swift.


3

Ho avuto lo stesso avvertimento, anche se la mia app sembrava funzionare correttamente. Il problema era che durante l'esecuzione di Editor> Crea sottoclasse NSManagedObject nell'ultima schermata ho usato la posizione di gruppo predefinita, senza target visualizzati o controllati, che ha salvato la sottoclasse nella directory superiore di MyApp in cui si trovava MyApp.xcodeproj.
L'avviso è andato via quando invece ho cambiato il gruppo per essere nella sottocartella MyApp e controllato la destinazione MyApp.


2

Le risposte di cui sopra sono state utili. Questo rapido controllo di integrità potrebbe farti risparmiare un po 'di tempo. Vai in Progetto> Crea fasi> Compila fonti e rimuovi xcdatamodeld e i file del modello con il pulsante "-", quindi aggiungili nuovamente con il pulsante "+". Ricostruisci: potrebbe occuparsene.


2

A proposito, fai attenzione a ciò che aggiungi come prefisso: la mia app si chiama "ABC-def" e Xcode ha convertito il "-" in un "_".

Per sicurezza, cerca nel finder, trova i tuoi file di progetto e vedi cosa dice per il tuo modello di dati (ad esempio "ABC_def.xcdatamodeld") e usa ciò che è scritto ESATTAMENTE !!!


1

Le risposte di cui sopra mi hanno aiutato a risolvere diversi problemi connessi con Objective-C (forse aiuterà qualcuno):

Se hai riformattato i nomi delle entità, non dimenticare di cambiare "Classe" anche in "Pannello Utilità".


0

Le risposte di cui sopra mi hanno aiutato, ma questo può aiutare qualcuno. Se come me li hai fatti e stai ancora riscontrando un problema, ricorda semplicemente di "pulire il tuo progetto". Per XCode8, Prodotto> Pulisci. Quindi corri di nuovo.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.