2010-02-20 25 views
7

Próbuję utworzyć aplikację na telefon iPhone, w której użytkownik może dodawać wpisy. Gdy naciśnie nowy wpis, pojawi się okienko z prośbą o podanie pewnych informacji. Następnie może nacisnąć "Anuluj" lub "Zapisz", aby odrzucić dane lub zapisać je na dysku.Program NSUndoManager cofnąć nie pracuje z danymi podstawowymi

Do zapisywania używam architektury Core Data, która działa całkiem dobrze. Jednak nie mogę uruchomić przycisku "Anuluj". Kiedy pojawi się okno, prosząc o informacje, tworzę nowy obiekt w kontekście obiektu zarządzanego (MOC). Następnie, gdy użytkownik naciśnie przycisk anulowania, próbuję użyć menedżera NSUndoManager należącego do MOC.

Chciałbym to zrobić również za pomocą zagnieżdżonych grup cofania, ponieważ mogą istnieć grupy zagnieżdżone.

Aby to przetestować, napisałem prostą aplikację. Aplikacja jest tylko szablonem "aplikacji opartej na oknach" z włączoną obsługą danych podstawowych. Dla modelu Core Data tworzę pojedynczy obiekt o nazwie "Entity" z całkowitym atrybutem "x". Następnie w aplikacjiDidFinishLaunching dodaję ten kod:

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

Pomysł jest prosty. Spróbuj wstawić nowy obiekt Entity, cofnij go, pobierz wszystkie obiekty Entity w MOC i wydrukuj je. Jeśli wszystko działało poprawnie, na końcu nie powinno być żadnych obiektów.

Jednak uzyskać ten wynik:

[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 

Jak widać, obiekt jest obecny w MOC po próbuję cofnąć jej tworzenia. Jakieś sugestie co do tego, co robię źle?

+0

Witam Mam ten sam problem. Znalazłeś rozwiązanie? Czy próbowałeś użyć "cofnij" zamiast "undoNestedGroup"? Dzięki gonso – gonso

Odpowiedz

13

Twój problem wynika z faktu, że w przeciwieństwie do OS X, kontekst obiektu zarządzanego iPhone'a nie zawiera domyślnie menedżera cofania. Musisz jednoznacznie dodać.

Zmień wygenerowany kod w delegata aplikacji dla właściwości managedObjectContext wyglądać tak:

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

} 

Po dokonaniu tej zmiany, komunikat 2-cia dziennika nie jest już wydrukowana.

nadzieję, że pomoże ...

Dave

+2

Właśnie znalazłem to podczas Googling podobne pytanie. Dave, zakładam, że istnieje dobry powód, że UndoManager jest domyślnie zerowy? Na przykład, jeśli pójdę do przodu i wprowadzę to w życie, czy dostanę związane z pamięcią bóle głowy? –

4

Próbowałem podejście Dave, ale nie działa dla mnie. W końcu znalazłem rozwiązanie w przykładzie Apple CoreDataBooks

Sztuką jest stworzenie nowego kontekstu, który współdzieli koordynatora z kontekstem aplikacji. Aby odrzucić zmiany, których nie potrzebujesz, po prostu odrzuć nowy obiekt kontekstu. Ponieważ współdzielisz koordynatora, zapisując aktualizacje w głównym kontekście.

Oto moja adaptowana wersja, w której do utworzenia kontekstu tymczasowego używam statycznego obiektu do utworzenia nowego obiektu 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; 
} 

Mam nadzieję, że to pomaga

Gonso

+0

Co się stanie, jeśli Twój zapis nie powiedzie się? W jaki sposób zamierzasz cofnąć te zmiany, które już zostały wprowadzone do kontekstu, a następnie spowodowały niepowodzenie? Na przykład. uprawomocnienie. – malhal

0

Powinien działać. Czy poprawnie przypisałeś menedżera cofania do obiektu managedObjectContext? Jeśli słusznie to zrobiłeś, domyślnie włączono rejestrację cofania i powinieneś być gotowy.Istnieje dobry artykuł na temat podstawowych danych here. Istnieje dobry samouczek dotyczący podstawowych danych i NSUndoManager here. Nadzieja, która pomaga.