Неможливо знайти конкретний підклас NSManagedObject


136

Я працюю над розробкою програми з основними даними. Коли я створив екземпляр, використовуючи:

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

Я отримав попередження у журналі:

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

Як я можу це виправити?

І ще одне питання, як я можу визначити метод екземпляра в підкласі NSManagedObject?

Редагувати:

Я вказав клас сутності як на наступному скріншоті:

введіть тут опис зображення


7
Ви встановили префікс назви класів сущностей з назвою модуля, як це зафіксовано в Реалізації підкласів об'єктів, керованих основними даними ?
Мартін

@MartinR: Дивіться оновлення мого питання.
MsrButterfly

2
Клас повинен бути "YourAppName.User", дивіться документацію (посилання в моєму попередньому коментарі).
Мартін Р

@MartinR: Дякую за допомогу. Це працює.
MsrButterfly

Найкраще видалити ці класи та створити їх знову. Це спрацювало для мене
Абхішек

Відповіді:


220

Оновлення для Xcode 7 (остаточне): Попередження назви модуля до класу (як у Xcode 6 та ранніх бета-версіях Xcode 7) більше не потрібно. Документація Apple, що реалізує підкласи об'єктів, керовані основними даними, оновлена ​​відповідно.

Зараз інспектор Моделі даних має два поля "Клас" та "Модуль" для суб'єкта:

введіть тут опис зображення

Коли ви створюєте підклас керованого об'єкта Swift для сутності, поле "Модуль" встановлюється на "Модуль поточного продукту", і за допомогою цього налаштування створення екземплярів працює як в основному додатку, так і в одиничних тестах. Підклас керованого об’єкта не повинен бути позначений @objc(classname)(це спостерігалось у https://stackoverflow.com/a/31288029/1187415 ).

Крім того, ви можете спорожнити поле "Модуль" (воно покаже "Ні") і позначити підкласи керованого об'єкта за допомогою @objc(classname)(це спостерігалось у https://stackoverflow.com/a/31287260/1187415 ).


Зауваження: Ця відповідь спочатку була написана для Xcode 6. У різних бета-версіях Xcode 7 відбулися деякі зміни стосовно цієї проблеми. Оскільки це прийнята відповідь з багатьма оновленнями та посиланнями на неї, я спробував підсумувати ситуацію для поточної остаточної версії Xcode 7.

Я провів і своє власне "дослідження", і прочитав усі відповіді як на це питання, так і на подібне запитання CoreData: попередження: Неможливо завантажити клас з назвою . Таким чином, атрибуція стосується всіх, навіть якщо я їх не перелічую конкретно!


Попередня відповідь для Xcode 6 :

Як задокументовано у впровадженні підкласів об'єктів з керованими базовими даними , ви повинні префіксувати ім’я класів сущностей у полі Class у інспекторі модельної сутності з назвою вашого модуля, наприклад "MyFirstSwiftApp.User".


2
Цей працює для мене. Питання: Що робити, якщо основні дані включені в рамки, як встановити префікс імені підкласу ManagedObject, оскільки фактичного додатку ще немає?
Allan Macatingrao

9
@Allan: Ви можете спробувати @objc(ClassName)метод, запропонований у відповіді Крістера.
Мартін Р

8
Це працює, але як тільки я встановив ім'я класу "APPNAME.User" в інспекторі сутності, я не можу відновити класи класів: Xcode, здається, плутається з префіксом, і він генерує файл / клас з ім'ям APPNAME. Я щось пропускаю?
Паскаль Бурк

1
Що робити, якщо ви отримуєте цю помилку в Objective-C під час використання основних даних у статичній бібліотеці?
Джордж Таскос

1
@Suragch: Зараз я остаточно оновив відповідь, сподіваюся, що зараз все правильно.
Martin R

62

Так само, як побічна нота. у мене було те саме питання. І все, що мені потрібно було зробити, - це додати @objc(ClassName)до файлу мого класу.

Приклад:

@objc(Person)
class Person { }

І це вирішило моє питання.


1
Таким чином ви визначили typealias (<% ProjectName%>. Person -> Person) в Objective-C, тому воно працює.
MsrButterfly

Здається, Apple забула повністю перетворити його на швидкий .. не знаю чому, але це виправило це для мене досить м’яко
Jiří Zahálka

7
Це особливо корисно, якщо у вас є проект з декількома цілями, де кожна ціль поділяє модель CoreData. У цих випадках неможливо приєднати назву класу до ідентифікатора цілі, оскільки модель CD стане корисною лише для однієї з цілей.
djbp

@djbp І "чому ні?" Я хотів би знати. Мені подобається концепція простору імен, але це змусило мене викинути свій MacBook у вікно (у мене є додаток із розширенням, і я потрапив на цю проблему під час запуску розширення). Має бути "правильний" спосіб зробити це з просторами імен, я просто не можу це зрозуміти.
S'pht'Kr

Але це працювало для мене під час роботи з спільними моделями даних у робочій області
naz

31

Прийнята відповідь на це питання допомогла мені вирішити те саме питання, але у мене був застереження, який я вважав корисним для інших. Якщо у вашому імені проекту (модуля) є пробіл, його слід замінити на підкреслення. Наприклад:

Суб’єкт: MyEntity Class: My_App_Name.MyClass


Саме те, що я шукав! Ура!
manosim

Коли ми встановлюємо ім'я класу за допомогою AppName.ClassName, Xcode 9 видаляє крапку і створює клас без крапки. Тож цього вже немає в Xcode 9. *.
yo2bh


9

Залежно від того, чи працює ви як додаток проти тестів, проблема може полягати в тому, що додаток шукає, <appName>.<entityName>і коли він працює як тест, він виглядає як <appName>Tests.<entityName>. Я зараз використовую рішення (Xcode 6.1) - НЕ заповнювати Classполе в інтерфейсі CoreData, а робити це замість коду.

Цей код виявить, чи ви працюєте як додаток проти тестів, і використовувати правильне ім'я модуля та оновить 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
Я спробував ваше рішення, але я отримую "фатальну помилку: елемент NSArray не вдався відповідати типу Swift Array Element" при передачі NSManagedObject його фактичному класу. Насправді не під час кастингу, а при спробі перейти в цикл.
Родріго Руїз

1
Цей приклад не працює, якщо у вас є будь-яка спадщина у вашій моделі. Для кожної нової сутності вам також потрібно перебирати субентити та оновлювати їх новими створеними вами об'єктами.
Антон

8

Якщо ви використовуєте дефіс у назві свого проекту, наприклад "My-App", тоді замість дефісу використовуйте підкреслення, наприклад "My_App.MyManagedObject". Загалом, подивіться на ім'я файлу xcdatamodeld і використовуйте той же префікс, що і в цьому імені. Тобто "My_App_1.xcdatamodeld" вимагає префікса "My_App_1"


1
Ого. Дякую, дякую, дякую. Мені було б цікаво дізнатись, де в документах Apple цей маленький самородок :)
nh32rg

5

Це може допомогти тим, хто відчуває ту саму проблему. Я був із Swift 2 та Xcode 7 beta 2.

У моєму випадку рішення було прокоментувати @objc(EntityName)в EntityName.swift.


3

У мене було таке ж попередження, хоча, здається, мій додаток працює нормально. Проблема полягала в тому, що під час запуску редактора> Створити підклас NSManagedObject на останньому екрані я використовував розташування групи за замовчуванням, без цілей, які не відображалися та не перевірялися, що зберігало підклас у верхній папці MyApp, де знаходився MyApp.xcodeproj.
Попередження пройшло, коли я замінив групу на підпапку MyApp і перевірив ціль MyApp.


2

Наведені вище відповіді були корисними. Ця швидка перевірка стану здоров'я може заощадити певний час. Перейдіть до проекту> Фази збірки> Зберіть джерела та видаліть свій xcdatamodeld та файли моделі за допомогою кнопки «-», а потім додайте їх знову за допомогою кнопки «+». Перебудувати - це може подбати про це.


2

До речі, будьте обережні, що ви додаєте як префікс: Мій додаток називається "ABC-def", а Xcode перетворив "-" в "_".

Щоб безпечно заглянути в пошук, знайдіть свої файли проекту і подивіться, що він пише для вашої моделі даних (наприклад, "ABC_def.xcdatamodeld") і використовуйте те, що там написано ТОЧНО !!!


1

Наведені вище відповіді допомогли мені вирішити різні питання, пов’язані з Objective-C (можливо, це комусь допоможе):

Якщо ви реконструювали назви юридичних осіб, не забудьте також змінити "Клас" на "Панель утиліт".


0

Наведені вище відповіді допомогли мені, але це може комусь допомогти. Якщо такі, як я, ви їх зробили і все ще відчуваєте проблеми, не забудьте просто "очистити свій проект". Для XCode8, Продукт> Очистити. Потім знову біжи.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.