Não foi possível encontrar a subclasse específica de NSManagedObject


136

Estou trabalhando no desenvolvimento de um aplicativo com o Core Data. Quando criei uma instância usando:

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

Recebi um aviso no log:

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

Como eu poderia consertar isso?

E outra pergunta, como posso definir um método de instância na subclasse NSManagedObject?

Editar:

Especifiquei a classe da entidade como na captura de tela a seguir:

insira a descrição da imagem aqui


7
Você prefixou o nome da classe de entidades com o nome do módulo, conforme documentado em Implementando subclasses de objeto gerenciado por dados principais ?
— Martin R

@ Martinin: Veja a atualização da minha pergunta.
— MsrButterfly

2
A classe deve ser "YourAppName.User", consulte a documentação (link no meu comentário anterior).
— Martin R

@ Martinin: Obrigado pela sua ajuda. Funciona.
— MsgButterfly

O melhor é excluir essas classes e recriá-las. Isso funcionou para mim
— Abhishek

Respostas:


220

Atualização para o Xcode 7 (final): A adição do nome do módulo à classe (como no Xcode 6 e nas versões beta anteriores do Xcode 7) não é mais necessária. A documentação da Apple Implementando subclasses de objeto gerenciado por dados principais foi atualizada de acordo.

O inspetor de modelo de dados agora possui dois campos "Classe" e "Módulo" para uma entidade:

insira a descrição da imagem aqui

Quando você cria uma subclasse de objeto gerenciado Swift para a entidade, o campo "Módulo" é definido como "Módulo atual do produto" e, com essa configuração, a criação de instâncias funciona tanto no aplicativo principal quanto nos testes de unidade. A subclasse de objeto gerenciado não deve ser marcada com @objc(classname)(isso foi observado em https://stackoverflow.com/a/31288029/1187415 ).

Como alternativa, você pode esvaziar o campo "Módulo" (ele mostrará "Nenhum") e marcar as subclasses de objetos gerenciados com @objc(classname)(isso foi observado em https://stackoverflow.com/a/31287260/1187415 ).


Observação: Esta resposta foi originalmente escrita para o Xcode 6. Houve algumas alterações nas várias versões beta do Xcode 7 com relação a esse problema. Como é uma resposta aceita com muitos upvotes e links para ela, tentei resumir a situação da atual versão final do Xcode 7.

Eu fiz minha própria "pesquisa" e li todas as respostas para essa pergunta e para a pergunta semelhante CoreData: warning: Não é possível carregar a classe nomeada . Portanto, a atribuição é atribuída a todos eles, mesmo que eu não os liste especificamente!


Resposta anterior para o Xcode 6 :

Conforme documentado em Implementando subclasses de objeto gerenciado por dados principais , você deve prefixar o nome da classe de entidades no campo Classe no inspetor de entidades do modelo com o nome do seu módulo, por exemplo "MyFirstSwiftApp.User".


2
Este está trabalhando para mim. Pergunta: E se os dados principais forem incluídos em uma estrutura, como prefixar o nome da subclasse ManagedObject, pois ainda não existe um aplicativo real?
— Allan Macatingrao

9
@ Allan: Você pode tentar o @objc(ClassName)método sugerido na resposta de Christer.
— Martin R

8
Funciona, mas depois de definir o nome da classe como "APPNAME.User" no inspetor de entidades, não consigo gerar novamente as classes do modelo: o Xcode parece estar confuso com o prefixo e gera um arquivo / classe com o nome NOME DO APLICATIVO. Estou esquecendo de algo?
— Pascal Bourque 26/09

1
E se você receber esse erro no Objective-C ao usar dados principais em uma biblioteca estática?
— George Taskos

1
@ Suragch: Agora, finalmente, atualizei a resposta, espero que tudo esteja correto agora.
— Martin R

62

Apenas como uma nota lateral. Eu tive o mesmo problema. E tudo que eu tinha que fazer era adicionar @objc(ClassName)no meu arquivo de classe.

Exemplo:

@objc(Person)
class Person { }

E isso resolveu meu problema.


1
Você definiu typealias (<% ProjectName%>. Person -> Person) no Objective-C dessa maneira, para que funcione.
— precisa saber é o seguinte

Parece que a Apple esqueceu de convertê-lo totalmente para o veloz .. não sei porquê, mas este fixa-lo para mim muito gentilmente
— Jiří Zahalka

7
Isso é particularmente útil se você tiver um projeto com vários destinos, em que cada destino compartilha o modelo CoreData. Nesses casos, não é possível prefixar o nome da classe com o do identificador de destino, pois isso torna o modelo de CD útil para apenas um dos destinos.
— djbp

@djbp E "por que não?" Eu gostaria de saber. Eu gosto do conceito de namespacing, mas isso me fez querer jogar meu MacBook pela janela (eu tenho um aplicativo com uma extensão e encontrei esse problema ao executá-la). Tem que haver uma maneira "certa" de fazer isso com namespaces, simplesmente não consigo descobrir.
— S'pht'Kr

Yup isso funcionou para mim quando se trabalha com modelos de dados compartilhados em um espaço de trabalho
— naz

31

A resposta aceita para essa pergunta me ajudou a resolver o mesmo problema, mas eu tinha uma ressalva que achava que seria útil para outras pessoas. Se o nome do seu projeto (módulo) tiver um espaço, você deverá substituir o espaço por um sublinhado. Por exemplo:

Entidade: MyEntity Classe: My_App_Name.MyClass


Exatamente o que eu estava procurando! Felicidades!
— manosim

Quando definimos o nome da classe com AppName.ClassName, o Xcode 9 remove o ponto e cria uma classe sem um ponto. Portanto, isso não está mais no Xcode 9. *.
— precisa saber é


9

Dependendo se você estiver executando como App vs Tests, o problema pode ser que o aplicativo está procurando <appName>.<entityName>e quando está sendo executado como teste <appName>Tests.<entityName>. A solução que eu uso no momento (Xcode 6.1) é NÃO preencher o Classcampo na interface do usuário CoreData e fazê-lo no código.

Esse código detectará se você está executando como App vs Tests e usa o nome correto do módulo e atualiza o 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
Tentei sua solução, mas estou recebendo "erro fatal: o elemento NSArray falhou ao corresponder ao tipo de elemento Swift Array" ao converter o NSManagedObject para sua classe real. Na verdade, não quando se projeta, mas ao tentar entrar em um loop for.
— Rodrigo Ruiz

1
Esse exemplo não funciona se você tiver algum tipo de herança em seu modelo. Para cada nova entidade, você também precisa iterar sobre os subentitos e atualizá-los com as novas entidades que você criou.
— Anton

8

Se você estiver usando um hífen no nome do seu projeto como "My-App", use um sublinhado em vez do hífen como "My_App.MyManagedObject". Em geral, observe o nome do arquivo xcdatamodeld e use o mesmo prefixo daquele nome. Ou seja, "My_App_1.xcdatamodeld" requer o prefixo "My_App_1"


1
Uau. Obrigado, obrigado, obrigado. Eu estaria interessado em saber onde nos docs da Apple que pequena pepita é :)
— nh32rg

5

Isso pode ajudar aqueles com o mesmo problema. Eu estava, com Swift 2 e Xcode 7 beta 2.

A solução no meu caso era para comentar @objc(EntityName)no EntityName.swift.


3

Eu tive o mesmo aviso, embora meu aplicativo parecesse funcionar bem. O problema era que, ao executar Editor> Criar subclasse NSManagedObject na última tela, usei o local padrão do grupo, sem destinos exibidos ou verificados, que salvou a subclasse no diretório MyApp superior, onde MyApp.xcodeproj estava localizado.
O aviso desapareceu quando, em vez disso, mudei o Grupo para a subpasta MyApp e verifiquei o destino MyApp.


2

As respostas acima foram úteis. Essa verificação rápida de sanidade pode poupar algum tempo. Vá para Projeto> Fases de construção> Compilar fontes e remova o xcdatamodeld e os arquivos de modelo com o botão "-" e adicione-os novamente com o botão "+". Reconstruir - isso pode cuidar disso.


2

A propósito, tenha cuidado com o que você adiciona como prefixo: Meu aplicativo é chamado "ABC-def" e o Xcode converteu o "-" em um "_".

Para estar seguro, procure o localizador, encontre os arquivos do projeto e veja o que diz para o seu modelo de dados (por exemplo "ABC_def.xcdatamodeld") e use o que está escrito EXATAMENTE !!!


1

As respostas acima me ajudaram a resolver problemas diferentes relacionados ao Objective-C (talvez isso ajude alguém):

Se você refatorou os nomes das entidades, não se esqueça de alterar "Classe" no "Painel de Utilitários" também.


0

As respostas acima me ajudaram, mas isso pode ajudar alguém. Se, como eu, você os fez e ainda está tendo um problema, lembre-se de simplesmente 'limpar seu projeto'. Para o XCode8, Produto> Limpar. Então corra novamente.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.