Pergunta

Estou tentando criar um aplicativo para iPhone onde o usuário possa adicionar entradas. Quando ele pressionar uma nova entrada, uma caixa aparecerá pedindo algumas informações. Em seguida, ele pode pressionar "Cancelar" ou "salvar" para descartar os dados ou salvá -los no disco.

Para salvar, estou usando a estrutura de dados principal, que funciona muito bem. No entanto, não consigo fazer o botão "Cancelar" funcionar. Quando a janela aparece, solicitando informações, crio um novo objeto no contexto do objeto gerenciado (MOC). Então, quando o usuário pressiona cancelar, tento usar o nsundomanager pertencente ao MOC.

Eu também gostaria de fazer isso usando grupos de desfazer aninhados, porque pode haver grupos aninhados.

Para testar isso, escrevi um aplicativo simples. O aplicativo é apenas o modelo "Aplicativo baseado em janela" com dados principais ativados. Para o modelo de dados principal, crio uma única entidade chamada "entidade" com atributo inteiro "x". Então, dentro do ApplicationDidfinishlaunching, adiciono este código:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

  // Override point for customization after app launch    

  unsigned int x=arc4random()%1000;
  [self.managedObjectContext processPendingChanges];
  [self.managedObjectContext.undoManager beginUndoGrouping];

  NSManagedObject *entity=[NSEntityDescription insertNewObjectForEntityForName:@"Entity" 
                                                        inManagedObjectContext:self.managedObjectContext];
  [entity setValue:[NSNumber numberWithInt:x] forKey:@"x"];
  NSLog(@"Insert Value %d",x);

  [self.managedObjectContext processPendingChanges];
  [self.managedObjectContext.undoManager endUndoGrouping];
  [self.managedObjectContext.undoManager undoNestedGroup];

  NSFetchRequest *fetchRequest=[[NSFetchRequest alloc] init];
  NSEntityDescription *entityEntity=[NSEntityDescription entityForName:@"Entity"
                                                inManagedObjectContext:self.managedObjectContext];
  [fetchRequest setEntity:entityEntity];
  NSArray *result=[self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
  for(entity in result) {
    NSLog(@"FETCHED ENTITY %d",[[entity valueForKey:@"x"] intValue]);
  }

    [window makeKeyAndVisible];
}

A ideia é simples. Tente inserir um novo objeto de entidade, desfazer -o, buscar todos os objetos de entidade no MOC e imprimi -los. Se tudo funcionou corretamente, não deve haver objetos no final.

No entanto, recebo esta saída:

[Session started at 2010-02-20 13:41:49 -0800.]
2010-02-20 13:41:51.695 Untitledundotes[7373:20b] Insert Value 136
2010-02-20 13:41:51.715 Untitledundotes[7373:20b] FETCHED ENTITY 136

Como você pode ver, o objeto está presente no MOC depois de tentar desfazer sua criação. Alguma sugestão sobre o que estou fazendo de errado?

Foi útil?

Solução

Seu problema é causado pelo fato de que, diferentemente do OS X, o contexto de objeto gerenciado pelo iPhone não contém um gerente de desfazer por padrão. Você precisa adicionar explicitamente um.

Altere o código gerado no delegado do aplicativo para a propriedade ManagedObjectContext para se parecer com a seguinte:

- (NSManagedObjectContext *) managedObjectContext {

    if (managedObjectContext != nil) {
        return managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        //add the following 3 lines of code
        NSUndoManager *undoManager = [[NSUndoManager alloc] init];
        [managedObjectContext setUndoManager:undoManager];
        [undoManager release];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }

    return managedObjectContext;

}

Depois de fazer essa alteração, a segunda mensagem de log não está mais impressa.

Espero que ajude...

Dave

Outras dicas

Eu tentei a abordagem de Dave, mas não funcionei para mim. Finalmente encontrei a solução no exemplo da Apple Coredatabooks

O truque é criar um novo contexto que compartilha o coordenador com o contexto do aplicativo. Para descartar as alterações que você não precisa fazer nada, basta descartar o novo objeto de contexto. Desde que você compartilha o coordenador, salvar atualiza seu contexto principal.

Aqui está minha versão adaptada, onde eu uso um objeto estático para o contexto temporário para criar um novo objeto ChannelMo.

//Gets a new ChannelMO that is part of the addingManagedContext
+(ChannelMO*) getNewChannelMO{

    // Create a new managed object context for the new channel -- set its persistent store coordinator to the same as that from the fetched results controller's context.
    NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init];
    addingManagedObjectContext = addingContext;

    [addingManagedObjectContext setPersistentStoreCoordinator:[[self getContext] persistentStoreCoordinator]];

    ChannelMO* aux = (ChannelMO *)[NSEntityDescription insertNewObjectForEntityForName:@"ChannelMO" inManagedObjectContext:addingManagedObjectContext];
    return aux;
}

+(void) saveAddingContext{
    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
    [dnc addObserver:self selector:@selector(addControllerContextDidSave:) 
                name:NSManagedObjectContextDidSaveNotification object:addingManagedObjectContext];

    NSError *error;
    if (![addingManagedObjectContext save:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:addingManagedObjectContext];

    // Release the adding managed object context.
    addingManagedObjectContext = nil;
}

Espero que ajude

Gonso

Deve funcionar. Você atribuiu corretamente o gerenciador de desfazer ao seu gerenciadoBjectContext? Se você fez isso com razão, por padrão, desfazer o registro ativado e você deve estar pronto. Há um bom artigo sobre dados principais aqui. Há um bom tutorial sobre dados principais e nsundomanager aqui. Espero que ajude.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top