Nie można znaleźć określonej podklasy NSManagedObject

136

Pracuję nad stworzeniem aplikacji z Core Data. Kiedy utworzyłem instancję przy użyciu:

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

Otrzymałem ostrzeżenie w dzienniku:

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

Jak mogłem to naprawić?

I kolejne pytanie, jak zdefiniować metodę instancji w podklasie NSManagedObject?

Edytować:

Podałem klasę jednostki, jak na poniższym zrzucie ekranu:

wprowadź opis obrazu tutaj

MsrButterfly
źródło
7
Czy nazwa klasy jednostek została poprzedzona nazwą modułu, zgodnie z dokumentacją w temacie Implementing Core Data Managed Object Subclasses ?
Martin R
@MartinR: Zobacz aktualizację mojego pytania.
MsrButterfly
2
Klasa powinna mieć nazwę „YourAppName.User”, zobacz dokumentację (link w moim poprzednim komentarzu).
Martin R
@MartinR: Dziękuję za pomoc. To działa.
MsrButterfly
Najlepiej jest usunąć te klasy i utworzyć je ponownie. To zadziałało dla mnie
Abhishek

Odpowiedzi:

220

Aktualizacja dla Xcode 7 (wersja ostateczna): Wstawianie nazwy modułu do klasy (jak w Xcode 6 i wczesnych wersjach beta Xcode 7) nie jest już konieczne. Dokumentacja Apple dotycząca implementacji podklas obiektów zarządzanych podstawowymi danymi została odpowiednio zaktualizowana.

Inspektor modelu danych ma teraz dwa pola „Klasa” i „Moduł” dla encji:

wprowadź opis obrazu tutaj

Podczas tworzenia podklasy obiektów zarządzanych Swift dla encji pole „Moduł” jest ustawione na „Bieżący moduł produktu”, a przy tym ustawieniu tworzenie instancji działa zarówno w aplikacji głównej, jak i testach jednostkowych. Podklasy obiektu zarządzanego nie mogą być oznaczone @objc(classname)(zaobserwowano to na stronie https://stackoverflow.com/a/31288029/1187415 ).

Alternatywnie możesz opróżnić pole „Moduł” (wyświetli się „Brak”) i oznaczyć podklasy obiektów zarządzanych za pomocą @objc(classname)(zaobserwowano to w https://stackoverflow.com/a/31287260/1187415 ).


Uwaga: Ta odpowiedź została pierwotnie napisana dla Xcode 6. W różnych wersjach beta Xcode 7 wprowadzono pewne zmiany w odniesieniu do tego problemu. Ponieważ jest to akceptowana odpowiedź z wieloma pozytywnymi opiniami i linkami do niej, próbowałem podsumować sytuację dla bieżącej ostatecznej wersji Xcode 7.

Zrobiłem zarówno własne „badania”, jak i przeczytałem wszystkie odpowiedzi zarówno na to pytanie, jak i na podobne pytanie CoreData: ostrzeżenie: Nie można załadować klasy o nazwie . Tak więc przypisanie dotyczy wszystkich z nich, nawet jeśli nie wymieniam ich szczegółowo!


Poprzednia odpowiedź dla Xcode 6 :

Jak opisano w sekcji Implementowanie podklas obiektów zarządzanych podstawowymi danymi , należy poprzedzić nazwę klasy jednostek w polu Klasa w inspektorze jednostek modelu nazwą modułu, na przykład „MyFirstSwiftApp.User”.

Martin R.
źródło
2
Ten pracuje dla mnie. Pytanie: Co się stanie, jeśli podstawowe dane są zawarte w strukturze, jak poprzedzić nazwę podklasy ManagedObject, skoro nie ma jeszcze rzeczywistej aplikacji?
Allan Macatingrao
9
@Allan: Możesz wypróbować @objc(ClassName)metodę sugerowaną w odpowiedzi Christera.
Martin R
8
Działa, ale po ustawieniu nazwy klasy na „APPNAME.User” w inspektorze encji nie mogę ponownie wygenerować klas modelu: Xcode wydaje się być zdezorientowany przez prefiks i generuje plik / klasę o nazwie NAZWA APLIKACJI. Czy coś mi brakuje?
Pascal Bourque
1
Co się stanie, jeśli otrzymasz ten błąd w Objective-C podczas korzystania z podstawowych danych w bibliotece statycznej?
George Taskos,
1
@Suragch: Wreszcie zaktualizowałem odpowiedź, mam nadzieję, że teraz wszystko jest w porządku.
Martin R
62

Tak na marginesie. miałem ten sam problem. Wszystko, co musiałem zrobić, to dodać @objc(ClassName)plik mojej klasy.

Przykład:

@objc(Person)
class Person { }

I to rozwiązało mój problem.

Christer
źródło
1
Zdefiniowano alias typu (<% ProjectName%>. Person -> Person) w Objective-C w ten sposób, więc to działa.
MsrButterfly
Wygląda na to, że Apple zapomniał w pełni przekonwertować go na swift ... nie wiem dlaczego, ale to naprawiło to dla mnie całkiem delikatnie
Jiří Zahálka
7
Jest to szczególnie przydatne, jeśli masz projekt z wieloma celami, w których każdy element docelowy współużytkuje model CoreData. W takich przypadkach nie można poprzedzić nazwy klasy nazwą identyfikatora celu, ponieważ powoduje to, że model CD jest przydatny tylko dla jednego z celów.
djbp
@djbp A „dlaczego nie?” Chciałbym wiedzieć. Podoba mi się koncepcja przestrzeni nazw, ale to sprawiło, że chciałem wyrzucić mojego MacBooka przez okno (mam aplikację z rozszerzeniem i napotkałem ten problem podczas uruchamiania rozszerzenia). Musi istnieć „właściwy” sposób na zrobienie tego z przestrzeniami nazw, po prostu nie mogę tego rozgryźć.
S'pht'Kr
Tak, to zadziałało podczas pracy z udostępnionymi modelami danych w obszarze roboczym
nazistowski
31

Przyjęta odpowiedź na to pytanie pomogła mi rozwiązać ten sam problem, ale miałem zastrzeżenie, które moim zdaniem będzie pomocne dla innych. Jeśli nazwa twojego projektu (modułu) zawiera spację, musisz zastąpić spację podkreśleniem. Na przykład:

Jednostka: MyEntity Klasa: My_App_Name.MyClass

Mannix
źródło
Dokładnie tego szukałem! Twoje zdrowie!
manosim
Kiedy ustawiamy nazwę klasy za pomocą AppName.ClassName, Xcode 9 usuwa kropkę i tworzy klasę bez kropki. Więc to nie jest już w Xcode 9. *.
yo2bh
17

Pamiętaj, aby usunąć swój moduł :

wprowadź opis obrazu tutaj

Bartłomiej Semańczyk
źródło
1
To rozwiązało mój problem!
simme
2
To rozwiązało mój problem.
Jason Huh
9

W zależności od tego, czy korzystasz z funkcji App vs Tests, problem może polegać na tym, że aplikacja szuka, <appName>.<entityName>a kiedy działa jako test, wygląda jak <appName>Tests.<entityName>. Rozwiązaniem, którego używam w tej chwili (Xcode 6.1) jest NIE wypełnianie Classpola w interfejsie użytkownika CoreData i zrobienie tego w kodzie.

Ten kod wykryje, czy korzystasz z funkcji App vs Tests i użyje właściwej nazwy modułu i zaktualizuje 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
źródło
1
Wypróbowałem Twoje rozwiązanie, ale otrzymuję komunikat „błąd krytyczny: element NSArray nie pasuje do typu elementu Swift Array” podczas rzutowania obiektu NSManagedObject na jego rzeczywistą klasę. Właściwie nie podczas rzucania samego siebie, ale podczas próby przejścia w pętlę for.
Rodrigo Ruiz
1
Ten przykład nie działa, jeśli masz jakieś dziedzictwo w swoim modelu. W przypadku każdej nowej encji musisz również iterować po podstronach i aktualizować je o nowe utworzone encje.
Anton
8

Jeśli używasz łącznika w nazwie projektu, np. „Moja aplikacja”, użyj podkreślenia zamiast łącznika, np. „Moja_Aplikacja.MojeManagedObject”. Ogólnie spójrz na nazwę pliku xcdatamodeld i użyj tego samego przedrostka, co w tej nazwie. To znaczy „My_App_1.xcdatamodeld” wymaga przedrostka „My_App_1”

Rien
źródło
1
łał. Dziekuję Dziekuję Dziękuję. Chciałbym wiedzieć, gdzie w dokumentach Apple znajduje się ten mały samorodek :)
nh32rg
5

Może to pomóc tym, którzy mają ten sam problem. Byłem, ze Swift 2 i Xcode 7 beta 2.

Rozwiązaniem w moim przypadku było wypowiedzieć się @objc(EntityName)w EntityName.swift.

enreas
źródło
3

Miałem to samo ostrzeżenie, chociaż moja aplikacja wyglądała na dobrze. Problem polegał na tym, że podczas uruchamiania Edytor> Utwórz podklasę NSManagedObject na ostatnim ekranie użyłem domyślnej lokalizacji grupy, bez wyświetlanych lub zaznaczonych obiektów docelowych, co zapisywało podklasę w górnym katalogu MyApp, w którym znajdował się MyApp.xcodeproj.
Ostrzeżenie zniknęło, gdy zamiast tego zmieniłem grupę na podfolder MyApp i sprawdziłem cel MyApp.

Daniel Ford
źródło
2

Powyższe odpowiedzi były pomocne. Ta szybka kontrola poczytalności może zaoszczędzić trochę czasu. Przejdź do Project> Build Phases> Compile Sources i usuń swój xcdatamodeld oraz pliki modelu za pomocą przycisku „-”, a następnie dodaj je z powrotem za pomocą przycisku „+”. Przebuduj - to może się tym zająć.

trevorgrayson
źródło
2

Nawiasem mówiąc, uważaj na to, co dodajesz jako przedrostek: Moja aplikacja nazywa się „ABC-def”, a Xcode przekształcił „-” w „_”.

Aby być bezpiecznym, zajrzyj do wyszukiwarki, znajdź pliki projektu i zobacz, co mówi o modelu danych (na przykład „ABC_def.xcdatamodeld”) i użyj tego, co tam jest napisane DOKŁADNIE !!!

Mikrofon
źródło
1

Powyższe odpowiedzi pomogły mi rozwiązać inny problem związany z Objective-C (może komuś pomoże):

Jeśli zrefaktorowałeś nazwy encji, nie zapomnij zmienić „Class” w „Utilities Panel”.

Vive
źródło
0

Powyższe odpowiedzi pomogły mi, ale może komuś pomóc. Jeśli tak jak ja wykonałeś je i nadal masz problem, pamiętaj, aby po prostu „wyczyścić swój projekt”. W przypadku XCode8, produkt> Wyczyść. Następnie biegnij ponownie.

Olaolu Akinsete
źródło
0

W Xcode 7 nazwy jednostek i klas mogą być takie same, ale Codegen powinno być definicją klasy. W takim przypadku nie będzie ostrzeżenia itp. Wprowadź tutaj opis obrazu

dcaric
źródło