2010-02-20 5 views
7

J'essaye de créer une application iPhone où l'utilisateur peut ajouter des entrées. Quand il appuie sur une nouvelle entrée, une boîte apparaîtra lui demandant des informations. Ensuite, il peut appuyer sur "Annuler" ou "Enregistrer" pour supprimer les données ou les enregistrer sur le disque. Pour sauvegarder, j'utilise le framework Core Data, qui fonctionne plutôt bien. Cependant, je ne peux pas obtenir le bouton "Annuler" pour fonctionner. Lorsque la fenêtre apparaît, demandant des informations, je crée un nouvel objet dans le contexte d'objet géré (MOC). Ensuite, lorsque l'utilisateur appuie sur annuler, j'essaie d'utiliser le NSUndoManager appartenant au MOC.NSUndoManager Annuler ne fonctionne pas avec les données de base

Je voudrais également le faire en utilisant des groupes d'annulation imbriqués, car il pourrait y avoir des groupes imbriqués.

Pour tester cela, j'ai écrit une application simple. L'application est simplement le modèle "Application basée sur la fenêtre" avec les données de base activées. Pour le modèle Core Data, je crée une entité unique appelée "Entity" avec l'attribut entier "x". Puis à l'intérieur du applicationDidFinishLaunching, ajouter ce code:

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

L'idée est simple. Essayez d'insérer un nouvel objet Entity, annulez-le, récupérez tous les objets Entity dans le MOC et imprimez-les. Si tout fonctionnait correctement, il ne devrait pas y avoir d'objets à la fin.

Cependant, je reçois cette sortie:

[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 

Comme vous pouvez le voir, l'objet est présent dans le MOC après que j'essaie de défaire sa création. Des suggestions sur ce que je fais mal?

+0

Salut Im ayant le même problème. Avez-vous trouvé une solution? Avez-vous essayé d'utiliser "undo" au lieu de "undoNestedGroup"? Merci gonso – gonso

Répondre

13

Votre problème est dû au fait que, contrairement à OS X, le contexte d'objet géré de l'iPhone ne contient pas de gestionnaire d'annulation par défaut. Vous devez en ajouter un explicitement.

Changer pour ressembler à ceci le code généré dans le délégué de l'application de la propriété managedObjectContext:

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

} 

Après avoir fait ce changement, le 2ème message du journal n'est plus imprimé.

espoir qui aide ...

Dave

+2

Je viens de trouver cela en recherchant une question similaire. Dave, je suppose qu'il y a une bonne raison pour que le undoManager soit nul par défaut? Par exemple, si je vais de l'avant et que je l'applique, est-ce que je vais avoir des maux de tête liés à la mémoire? –

4

j'ai essayé l'approche Dave, mais ne fonctionne pas pour moi. J'ai finalement trouvé la solution dans l'exemple d'Apple CoreDataBooks

L'astuce consiste à créer un nouveau contexte qui partage le coordinateur avec le contexte de votre application. Pour rejeter les modifications, vous n'avez pas besoin de faire quelque chose, il suffit de rejeter le nouvel objet de contexte. Puisque vous partagez le coordinateur, l'enregistrement met à jour votre contexte principal.

Voici ma version adaptée, où j'utilise un objet statique pour le contexte temporaire pour créer un nouvel objet 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; 
} 

J'espère que cela aide

Gonso

+0

Que faire si votre sauvegarde échoue? Comment allez-vous défaire ces changements qui ont déjà été mis dans le contexte et ensuite causé l'échec? Par exemple. validation. – malhal

0

Il devrait fonctionner. Avez-vous correctement affecté le gestionnaire d'annulation à votre managedObjectContext? Si vous l'avez fait à juste titre, l'annulation de l'enregistrement est activée par défaut, et vous devriez être prêt à partir.Il y a un bon article sur les données de base here. Il y a un bon tutoriel sur les données de base et NSUndoManager here. J'espère que cela pourra aider.

Questions connexes