Como faço para copiar ou mover um NSManagedObject de um contexto para outro?

Eu tenho o que eu suponho que é uma configuração bastante padrão, com um MOC de rascunho que nunca é salvo (contendo um monte de objects baixados da web) e outro MOC permanente que persiste objects. Quando o usuário seleciona um object do zeroMOC para include em sua biblioteca, eu quero 1) remover o object do zeroMOC e inserir em permanentMOC ou 2) copiar o object em permanentMOC. O Core Data FAQ diz que posso copiar um object como este:

NSManagedObjectID *objectID = [managedObject objectID]; NSManagedObject *copy = [context2 objectWithID:objectID]; 

(Nesse caso, context2 seria permanentMOC.) No entanto, quando faço isso, o object copiado está com falha; os dados são inicialmente não resolvidos. Quando é resolvido, mais tarde, todos os valores são nulos; Nenhum dos dados (atributos ou relacionamentos) do managedObject original é realmente copiado ou referenciado. Portanto, não consigo ver nenhuma diferença entre usar esse método objectWithID: e apenas inserir um object inteiramente novo em permanentMOC usando insertNewObjectForEntityForName :.

Eu percebo que posso criar um novo object em permanentMOC e copiar manualmente cada par de valor-chave do object antigo, mas não estou muito feliz com essa solução. (Eu tenho um número de diferentes objects gerenciados para os quais eu tenho este problema, então eu não quero ter que escrever e atualizar a cópia: methods para todos eles, enquanto eu continuo desenvolvendo). Existe uma maneira melhor?

Primeiro, ter mais de um NSManagedObjectContext em um único thread não é uma configuração padrão. 99% do tempo você só precisa de um contexto e isso resolverá essa situação para você.

Por que você acha que precisa de mais de um NSManagedObjectContext ?

Atualizar

Esse é realmente um dos poucos casos de uso que eu vi onde isso faz sentido. Para fazer isso, você precisa fazer uma cópia recursiva do object de um contexto para o outro. O stream de trabalho seria o seguinte:

  1. Criar novo object em contexto persistente
  2. obtenha um dictionary dos atributos do object de origem (use -dictionaryWithValuesForKeys e -[NSEntityDescription attributesByName] para fazer isso.
  3. definir o dictionary de valores para o object de destino (usando -setValuesForKeysWithDictionary )
  4. Se você tiver relacionamentos, precisará fazer essa cópia recursivamente e percorrer os relacionamentos de forma codificada (para evitar alguma lógica circular) ou usando o -[NSEntityDescription relationshipsByName]

Como mencionado por outro, você pode fazer o download do código de amostra do meu livro em The Pragmatic Programmers Data Book e ver uma solução para esse problema. Claro que no livro eu discuto mais a fundo 🙂

A documentação é enganosa e incompleta. Os methods objectID não copiam objects, eles simplesmente garantem que você obteve o object específico que você queria.

O context2 no exemplo é, de fato, o contexto de origem e não o destino. Você está recebendo um valor nulo porque o contexto de destino não tem object com esse ID.

A cópia de objects gerenciados é bastante envolvida devido à complexidade do gráfico de objects e à maneira como o contexto gerencia o gráfico. Você precisa recriar o object copiado em detalhes no novo contexto.

Aqui estão alguns exemplos de código que eu recortei do código de exemplo do Core Data do programador pragmático : API da Apple para persistir dados no Mac OS X. (Você pode baixar todo o código do projeto sem comprar o livro no site Pragmatic.) Ele deve fornecer uma idéia aproximada de como copiar um object entre o contexto.

Você pode criar algum código de base que copie objects, mas as particularidades dos relacionamentos de cada gráfico de object geralmente significam que você precisa personalizar para cada modelo de dados.

Tive o mesmo problema e encontrei este artigo sobre entidades desconectadas criadas que poderiam ser posteriormente adicionadas ao contexto: http://locassa.com/temporary-storage-in-apples-coredata/

A idéia é que você tenha um NSManagedObject porque você estará armazenando objects no database. Meu obstáculo é que muitos desses objects são baixados via API HTTP e eu quero jogar fora a maioria deles no final da session. Pense em um stream de postagens de usuários e só quero salvar as que foram favoritas ou salvas como rascunho.

Eu crio todas as minhas postagens usando

 + (id)newPost { NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:self.managedObjectContext]; Post *post = [[Post alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:nil]; return post; } 

e, em seguida, os posts são inseridos no contexto do object gerenciado local quando são favorecidos

 + (BOOL)favoritePost:(Post *)post isFavorite:(BOOL)isFavorite { // Set the post's isFavorite flag post.isFavorite = [NSNumber numberWithBool:isFavorite]; // If the post is being favorited and not yet in the local database, add it NSError *error; if (isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] == nil) { [self.managedObjectContext insertObject:post]; } // Else if the post is being un-favorited and is in the local database, delete it else if (!isFavorite && [self.managedObjectContext existingObjectWithID:post.objectID error:&error] != nil) { [self.managedObjectContext deleteObject:post]; } // If there was an error, output and return NO to indicate a failure if (error) { NSLog(@"error: %@", error); return NO; } return YES; } 

Espero que ajude.

Você precisa ter certeza de que está salvando o contexto no qual o managedObject reside. Para obter o mesmo object em um contexto diferente, ele precisa estar presente no armazenamento persistente.

De acordo com a documentação , objectWithID: sempre retorna um object. Portanto, o fato de que a falha é resolvida para um object, todos os valores nil implicam que ele não está localizando seu object no armazenamento persistente.