2010-02-20 15 views
7

Estoy tratando de crear una aplicación de iPhone donde el usuario puede agregar entradas. Cuando presiona una nueva entrada, aparecerá un recuadro pidiéndole alguna información. Luego puede presionar "Cancelar" o "Guardar" para descartar los datos o guardarlos en el disco.NSUndoManager deshacer No funciona con datos centrales

Para guardar, utilizo el marco de Datos Core, que funciona bastante bien. Sin embargo, no puedo hacer que funcione el botón "Cancelar". Cuando aparece la ventana, solicitando información, creo un nuevo objeto en el contexto del objeto administrado (MOC). Luego, cuando el usuario presiona cancelar, trato de usar NSUndoManager que pertenece al MOC.

También me gustaría hacerlo utilizando grupos de deshacer anidados, porque podría haber grupos anidados.

Para probar esto, escribí una aplicación simple. La aplicación es simplemente la plantilla "Aplicación basada en la ventana" con Core Data habilitado. Para el modelo de Datos básicos, creo una única entidad llamada "Entidad" con el atributo entero "x". Luego dentro de la aplicaciónDinFinishLaunching, agrego 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]; 
} 

La idea es simple. Intente insertar un nuevo objeto Entity, deshacerlo, recuperar todos los objetos Entity en el MOC e imprimirlos. Si todo funcionó correctamente, no debería haber objetos al final.

Sin embargo, me sale esta salida:

[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 se puede ver, el objeto está presente en el MOC después de que intento de deshacer su creación. ¿Alguna sugerencia sobre lo que estoy haciendo mal?

+0

Hola Estoy teniendo el mismo problema. ¿Encontraste una solución? ¿Ha intentado utilizar "deshacer" en lugar de "deshacer grupo desatendido"? Gracias gonso – gonso

Respuesta

13

Su problema está causado por el hecho de que, a diferencia de OS X, el contexto del objeto administrado de iPhone no contiene un administrador de deshacer de manera predeterminada. Necesitas agregar explícitamente uno.

Cambiar el código generado en el delegado de la aplicación para la propiedad managedObjectContext a tener este aspecto:

- (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; 

} 

Después de hacer ese cambio, el segundo mensaje de registro ya no se imprime.

Espero que ayude ...

de Dave

+2

Acabo de encontrar esto mientras busco en Google una pregunta similar. Dave, supongo que hay una buena razón para que el DeshacerManager sea nulo por defecto. Al igual que si sigo adelante y lo implemento, ¿tendré dolores de cabeza relacionados con la memoria? –

4

me trató enfoque de Dave, pero no funcionó para mí. Finalmente encontré la solución en el ejemplo de Apple CoreDataBooks

El truco está en crear un nuevo contexto que comparta el coordinador con el contexto de tu aplicación. Para descartar los cambios, no necesita hacer nada, solo descarte el nuevo objeto de contexto. Como comparte el coordinador, guarda las actualizaciones de su contexto principal.

Aquí está mi versión adaptada, donde uso un objeto estático para el contexto temporal para crear un nuevo 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 ayude

Gonso

+0

¿Qué sucede si tu guardado falla? ¿Cómo va a deshacer los cambios que ya se han puesto en el contexto y luego ha causado el error? P.ej. validación. – malhal

0

Se debe trabajar. ¿Asignó correctamente el administrador de deshacer a su managedObjectContext? Si lo ha hecho correctamente, de manera predeterminada tiene habilitado el registro de deshacer, y debería estar listo para continuar.Hay un buen artículo sobre datos básicos here. Hay un buen tutorial sobre datos básicos y NSUndoManager here. Espero que ayude.

Cuestiones relacionadas