O que tenho que fazer para que o Core Data migre automaticamente os modelos?

96

Eu li a documentação sobre migração automática / leve para modelos de Core Data - mas estou tendo problemas para implementá-la.

Pelo que entendi, o aplicativo deve perceber que o modelo que possui e o modelo que existe em um dispositivo já não são os mesmos. Se você adicionou apenas atributos ou relacionamentos e mudanças simples semelhantes, o modelo deve ser atualizado automaticamente.

Quaisquer ponteiros - eu preciso definir algo no Xcode?

Grouchal
fonte

Respostas:

138

Agora descobri que isso é bastante simples - assim que você souber onde procurar.

Em meu AppDelegate, configurei o NSPersistentStoreCoordinator - e você precisa adicionar algumas opções a isso para instruí-lo a lidar com a migração automática:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:

[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,

[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

NSError *error;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Handle error
    NSLog(@"Problem with PersistentStoreCoordinator: %@",error);
}

Então você precisa fazer um pequeno truque no xCode:

  1. Selecione seu arquivo xcdatamodel
  2. Selecione o Menu Design no topo - então Modelo de Dados - então escolha Adicionar Versão do Modelo
  3. Seu arquivo xcdatamodel será movido para um novo diretório com o mesmo nome de seu arquivo xcdatamodel, mas com a extensão xcdatamodeld - haverá um segundo arquivo neste diretório com um 2 no nome. Selecione o novo arquivo e, em seguida, Design-> Modelo de Dados-> Definir Versão Atual ( no Xcode 4 você faz isso )
  4. Se você já fez as alterações que tornaram seu projeto incompatível, retire essas alterações do arquivo xcdatamodel original. Se você ainda não fez as alterações - então apenas edite o arquivo 2.xcdatamodel (aquele que você acabou de criar na versão atual).
  5. Agora, quando você instalar esta versão em um dispositivo que tem o modelo antigo, ele fará upgrade automaticamente desse modelo para o novo modelo.

Isso parece ótimo e tão simples quanto eu queria - mas acho que você precisa ter cuidado durante o desenvolvimento ao alterar um modelo - caso contrário, você terá que criar uma nova versão para cada alteração.

Acho que o que farei é manter todos os arquivos alterados e, quando estiver pronto para implantar minha atualização, excluirei todos os arquivos intermediários e apenas implantarei com os modelos mais antigos e mais recentes.


ATUALIZAÇÃO (15/07/2011):

Obrigado a @ rockstarberlin por apontar que há documentação atualizada na apple:

Xcode 4: Definindo a versão atual de um modelo de objeto gerenciado

Atualização: 19/08/2013 melhor link:

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html

Grouchal
fonte
Sugiro a leitura do Guia de migração e controle de versão de dados principais, disponível no visualizador de documentos Xcode e em developer.apple.com.
Hunter
1
Eu não encontrei a resposta simplesmente - demorou um pouco para descobrir como fazer isso.
Grouchal
NSInferMappingModelAutomaticallyOption funciona bem, mas apenas para mapeamentos simples, como alterar o nome de um atributo. Para algo mais complicado (relacionamentos, remoção ou adição de entidades), você precisará adicionar um modelo de mapeamento. Se o Xcode reclamar que NSInferMappingModelAutomaticallyOption não foi declarado, adicione #import <CoreData / CoreData.h> ao arquivo de cabeçalho de delegado do aplicativo.
Elise van Looij
Eu adicionei algumas entidades ao meu modelo e recebi o infame erro "O modelo usado para abrir a loja é incompatível com o usado para criar a loja". Sua solução consertou! Muito obrigado!
Karsten Silz
1
Veja a resposta de Santthosh abaixo se estiver recebendo o erro "não é possível mesclar modelos com duas entidades diferentes chamadas" após seguir essas instruções.
benvolioT
14

Isso foi incrivelmente útil. A documentação da Apple estava - como sempre - lamentavelmente incompleta. Recomendo fazer uma compilação limpa, pois encontrei um erro "Não é possível mesclar modelos com duas entidades diferentes xxx" quando executei pela primeira vez depois de fazer essas alterações. A compilação limpa o consertou.

Scott Means
fonte
Uma compilação limpa corrigiu meus problemas também.
jrainbow
6

A resposta de Grouchal é perfeita ... mas se você ainda estiver tendo o "Não é possível mesclar modelos com duas entidades diferentes xxx", mesmo depois de limpar a compilação várias vezes ... Você pode ter problemas com a forma como o managedObjectModel está sendo carregado .. .vai dar uma olhada neste ... o que me ajudou a consertá-lo ..

principais problemas de migração de dados

Santthosh
fonte
3

Além disso, se você topou com este post, como eu, depois de obter o erro "O modelo usado para abrir a loja é incompatível com o usado para criar a loja" e você está apenas depurando usando o simulador e querendo substituir completamente o Com o modelo antigo instalado, você pode apenas reiniciar o aplicativo Simulador ou excluir seu aplicativo do simulador provavelmente também funcionaria.

Não me ocorreu tentar fazer isso até ler as postagens aqui, quando percebi que havia instalado o aplicativo no simulador e posteriormente alterado o modelo, causando o erro de tempo de execução mencionado acima.

dreyln
fonte
1

Para acompanhar a resposta de Santthosh, resolvi postar o trecho de código bem aqui. Você precisa criar seu managedObjectModel com, em initWithContentsOfURL:vez de, mergedModelFromBundles:caso contrário, você receberá o erro:

Não é possível mesclar modelos com duas entidades diferentes XXX e XXX

Se o seu arquivo de modelo for denominado "Modelo", veja como você cria o managedObjectModel:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL]; 

Crédito para esta postagem do blog .

samvermette
fonte
1

Eu tenho esse problema há anos e tentei todas essas respostas sem sucesso. Hoje eu finalmente descobri o que estava fazendo de errado. Problema muito simples, mas esqueci. Ao criar uma versão mais recente do modelo de dados, se estiver ADICIONANDO colunas, certifique-se de marcá-las como OPCIONAIS. Se você não fizer isso, a migração simples não funcionará porque os novos valores da coluna não serão preenchidos.

Assim que me certifiquei de que minhas novas colunas tinham "opcional" marcado, tentei a migração novamente e funcionou.

Brain2000
fonte
1

Eu tropecei neste post por causa de um problema diferente, mas o erro era " A configuração do modelo usado para abrir a loja é incompatível com o que foi usado para criar a loja. "

Aqui estava meu problema e a solução para ele. No meu modelo, estava usando configurações . Algumas das entidades foram armazenadas em um arquivo e as outras em um segundo arquivo. (Eu tenho alguns padrões que podem precisar ser baixados periodicamente, e seria uma dor incrível mesclá-los no todo). De qualquer forma, criei uma nova entidade. O programa parecia funcionar bem, mas sempre que eu saia, recebia o erro acima.

A solução ali foi olhar minhas configurações, perceber que eu tinha uma entidade que não estava em nenhuma das configurações e adicioná-la a uma. Corre como um sonho.

Isso não resolverá o problema do OP. Mas talvez alguma pessoa frustrada que desembarque aqui via google esteja no barco em que eu estava :)

The Cappy
fonte
0

iOS 4.0+

NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"model" withExtension:@"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
Stian Høiland
fonte
0

Pequenas edições nas incríveis instruções de @ Grouchal acima para o Xcode versão 5:

Antigo: 2. Selecione o Menu Design no topo - então Modelo de Dados - então escolha Adicionar Versão do Modelo

Versão 5+: 2. Selecione o menu Editor e, em seguida, Adicionar versão do modelo ..., digite o nome da versão e com base no modelo (selecione o modelo original da lista)

PGSeattle
fonte