2010-02-20 4 views
7

Ich versuche, eine iPhone-Anwendung zu erstellen, wo der Benutzer Einträge hinzufügen kann. Wenn er einen neuen Eintrag drückt, erscheint eine Box, die ihn nach Informationen fragt. Dann kann er entweder "Abbrechen" oder "Speichern" drücken, um die Daten zu verwerfen oder auf der Festplatte zu speichern.NSUndoManager rückgängig machen funktioniert nicht mit Core-Daten

Zum Speichern verwende ich das Core Data Framework, das ziemlich gut funktioniert. Ich kann jedoch die Schaltfläche "Abbrechen" nicht ausführen. Wenn das Fenster erscheint und nach Informationen fragt, erstelle ich ein neues Objekt im Kontext des verwalteten Objekts (MOC). Wenn der Benutzer dann Abbrechen drückt, versuche ich den zum MOC gehörenden NSUndoManager zu verwenden.

Ich würde es auch gerne mit geschachtelten Gruppen rückgängig machen, weil es verschachtelte Gruppen geben könnte.

Um dies zu testen, schrieb ich eine einfache Anwendung. Die Anwendung ist nur die Vorlage "Fensterbasierte Anwendung" mit aktivierten Kerndaten. Für das Core-Data-Modell erstelle ich eine einzelne Entität namens "Entity" mit dem Ganzzahlattribut "x". Dann füge ich innerhalb der applicationDidFinishLaunch diesen Code hinzu:

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

Die Idee ist einfach. Versuchen Sie, ein neues Entity-Objekt einzufügen, rückgängig zu machen, alle Entity-Objekte im MOC abzurufen und auszudrucken. Wenn alles richtig funktioniert hat, sollte es am Ende keine Objekte geben.

Allerdings bekomme ich diese Ausgabe:

[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 

Wie Sie sehen können, das Objekt in der MOC vorhanden ist, nachdem ich versuche, seine Schöpfung rückgängig zu machen. Irgendwelche Vorschläge, was ich falsch mache?

+0

Hallo Ich habe das gleiche Problem. Hast du eine Lösung gefunden? Haben Sie versucht, "undo" anstelle von "undoNestedGroup" zu verwenden? Dank gonso – gonso

Antwort

13

Ihr Problem wird dadurch verursacht, dass der iPhone-Kontext für verwaltete Objekte im Gegensatz zu OS X standardmäßig keinen Undo-Manager enthält. Sie müssen einen explizit hinzufügen.

Ändern Sie den generierten Code in der App Delegat für die managedObjectContext Eigenschaft wie folgt aussehen:

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

} 

Nachdem diese Änderung vornehmen, wird die zweite Log-Nachricht nicht gedruckt länger.

Hoffnung, das hilft ...

Dave

+2

Gerade gefunden, während Googling eine ähnliche Frage. Dave, ich nehme an, es gibt einen guten Grund, dass der UndoManager standardmäßig Null ist? Wenn ich zum Beispiel das umsetze, bekomme ich dann Kopfschmerzen im Kopf? –

4

habe ich versucht, Dave Ansatz, aber nicht für mich zu arbeiten. Ich fand schließlich die Lösung in Apples Beispiel CoreDataBooks

Der Trick besteht darin, einen neuen Kontext zu erstellen, der den Koordinator mit Ihrem App-Kontext teilt. Um die Änderungen zu verwerfen, müssen Sie einfach das neue Kontextobjekt verwerfen. Da Sie den Koordinator freigeben, wird beim Speichern der Hauptkontext aktualisiert.

Hier ist meine angepasste Version, wo ich ein statisches Objekt für den Temp-Kontext verwenden, um ein neues ChannelMO-Objekt zu erstellen.

//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; 
} 

Ich hoffe, es

Gonso

+0

Was passiert, wenn das Speichern fehlschlägt? Wie werden Sie die Änderungen rückgängig machen, die bereits in den Kontext gestellt wurden und dann das Scheitern verursacht haben? Z.B. Validierung. – malhal

0

hilft sollte es funktionieren. Haben Sie den Undo-Manager korrekt Ihrem managedObjectContext zugewiesen? Wenn Sie das richtig gemacht haben, hat es standardmäßig die Registrierung rückgängig gemacht, und Sie sollten gut gehen.Es gibt einen guten Artikel über Kerndaten here. Es gibt ein gutes Tutorial zu Kerndaten und NSUndoManager here. Ich hoffe, das hilft.

Verwandte Themen