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

136

Я работаю над разработкой приложения с Core Data. Когда я создал экземпляр, используя:

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?

Редактировать:

Я указал класс сущности, как на следующем скриншоте:

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

MsrButterfly
источник
7
Вы добавили в префикс имени класса сущностей имя модуля, как описано в разделе « Реализация подклассов управляемых объектов базовых данных» ?
Мартин Р
@MartinR: см. Обновление моего вопроса.
MsrButterfly
2
Класс должен быть "YourAppName.User", см. Документацию (ссылка в моем предыдущем комментарии).
Мартин Р
@MartinR: Спасибо за вашу помощь. Оно работает.
MsrButterfly
Лучше всего удалить эти классы и заново создать их. Это сработало для меня
Abhishek

Ответы:

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.

Я провел свое собственное «исследование» и прочитал все ответы на этот вопрос и на аналогичный вопрос CoreData: warning: Невозможно загрузить класс named . Таким образом, авторство относится ко всем из них, даже если я не перечислю их конкретно!


Предыдущий ответ для Xcode 6 :

Как описано в разделе « Реализация подклассов управляемых объектов базовых данных», необходимо добавить префикс имени класса сущностей в поле «Класс» в инспекторе сущностей модели к имени вашего модуля, например «MyFirstSwiftApp.User».

Мартин Р
источник
2
Этот работает на меня. Вопрос: Что, если основные данные включены в каркас, как добавить префикс имени подкласса ManagedObject, так как еще нет фактического приложения?
Аллан Макатинграо
9
@Allan: Вы можете попробовать @objc(ClassName)метод, предложенный в ответе Кристера.
Мартин Р
8
Это работает, но как только я установил имя класса «APPNAME.User» в инспекторе сущностей, я не могу перегенерировать классы модели: Xcode, похоже, смущен префиксом, и он генерирует файл / класс с именем НАЗВАНИЕ ПРИЛОЖЕНИЯ. Я что-то упускаю?
Паскаль Бурк
1
Что если вы получите эту ошибку в Objective-C при использовании основных данных в статической библиотеке?
Джордж Таскос
1
@Suragch: Теперь я наконец обновил ответ, я надеюсь, что сейчас все правильно.
Мартин Р
62

Просто как примечание. Я была такая же проблема. И все, что мне нужно было сделать, это добавить @objc(ClassName)в мой файл класса.

Пример:

@objc(Person)
class Person { }

И это решило мою проблему.

Кристер
источник
1
Вы определили typealias (<% ProjectName%>. Person -> Person) в Objective-C таким образом, чтобы он работал.
MsrButterfly
Похоже, Apple забыла полностью преобразовать его в быстрый. Не знаю почему, но это исправило это для меня довольно осторожно
Иржи Захалка
7
Это особенно полезно, если у вас есть проект с несколькими целями, где каждая цель использует модель CoreData. В этих случаях невозможно добавить префикс имени класса к идентификатору целевого идентификатора, поскольку это делает модель CD полезной только для одной из целей.
DJBP
@djbp и "почему бы и нет?" Я хотел бы знать. Мне нравится концепция пространства имен, но это заставило меня захотеть выбросить мой MacBook из окна (у меня есть приложение с расширением, и я столкнулся с этой проблемой при запуске расширения). Должен быть «правильный» способ сделать это с пространствами имен, я просто не могу понять это.
S'pht'Kr
Да, это сработало для меня при работе с общими моделями данных в рабочей области
naz
31

Принятый ответ на этот вопрос помог мне решить ту же проблему, но у меня было предостережение, которое, как я думал, будет полезно для других. Если в имени вашего проекта (модуля) есть пробел, вы должны заменить пробел подчеркиванием. Например:

Entity: MyEntity Class: My_App_Name.MyClass

Mannix
источник
Именно то, что я искал! Ура!
Маносим
Когда мы устанавливаем имя класса с помощью AppName.ClassName, Xcode 9 удаляет точку и создает класс без точки. Так что это больше не в Xcode 9. *.
yo2bh
17

Не забудьте удалить свой модуль :

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

Бартломей Семанчик
источник
1
Это исправило мою проблему!
Сим
2
Это исправило мою проблему.
Джейсон Ху
9

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

Этот код определит, работаете ли вы как App vs Tests, используете правильное имя модуля и обновите 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" при приведении NSManagedObject к его фактическому классу. На самом деле не во время приведения, а при попытке войти в цикл for.
Родриго Руис
1
Этот пример не работает, если в вашей модели есть какое-либо наследование. Для каждой новой сущности вам также нужно перебирать подузлы и обновлять их новыми созданными вами сущностями.
Антон
8

Если вы используете дефис в названии своего проекта, например, «My-App», тогда используйте дефис, например «My_App.MyManagedObject», вместо подчеркивания. В общем, посмотрите на имя файла xcdatamodeld и используйте тот же префикс, что и в этом имени. Т.е. для "My_App_1.xcdatamodeld" требуется префикс "My_App_1"

Rien
источник
1
Вот это да. Спасибо Спасибо спасибо. Мне было бы интересно узнать, где в документации Apple находится этот маленький самородок :)
nh32rg
5

Это может помочь тем, кто испытывает ту же проблему. Я был со Swift 2 и Xcode 7 beta 2.

Решением в моем случае было закомментировать @objc(EntityName)в EntityName.swift.

enreas
источник
3

У меня было то же предупреждение, хотя мое приложение работало нормально. Проблема заключалась в том, что при запуске Editor> Create NSManagedObject Subclass на последнем экране я использовал расположение группы по умолчанию, при этом целевые объекты не отображались и не проверялись, что сохраняло подкласс в верхнем каталоге MyApp, где находился MyApp.xcodeproj.
Предупреждение исчезло, когда я вместо этого изменил группу на подпапку MyApp и проверил цель MyApp.

Дэниел Форд
источник
2

Приведенные выше ответы были полезны. Эта быстрая проверка работоспособности может сэкономить вам время. Перейдите в Project> Build Phases> Compile Sources и удалите xcdatamodeld и файлы модели с помощью кнопки «-», а затем добавьте их обратно с помощью кнопки «+». Восстановить - это может позаботиться об этом.

trevorgrayson
источник
2

Кстати, будьте осторожны с тем, что вы добавляете в качестве префикса: мое приложение называется «ABC-def», а Xcode преобразовал «-» в «_».

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

Майк
источник
1

Приведенные выше ответы помогли мне решить другую проблему, связанную с Objective-C (может, кому-то это поможет):

Если вы реорганизовали имена сущностей, не забудьте также изменить «Класс» на «Панели утилит».

Vive
источник
0

Приведенные выше ответы помогли мне, но это может кому-то помочь. Если вы, как и я, сделали это и все еще испытываете проблемы, не забудьте просто «очистить свой проект». Для XCode8, Product> Clean. Тогда беги снова.

Олаолу Акинсете
источник