2010-02-20 11 views
7

Sto tentando di creare un'applicazione iPhone in cui l'utente può aggiungere voci. Quando preme una nuova voce, una finestra pop-up gli chiederà alcune informazioni. Quindi può premere "Annulla" o "Salva" per scartare i dati o salvarli su disco.NSUndoManager Annulla Non funziona con i dati principali

Per il salvataggio, sto utilizzando il framework Core Data, che funziona piuttosto bene. Tuttavia, non riesco a far funzionare il pulsante "Annulla". Quando si apre la finestra, chiedendo informazioni, creo un nuovo oggetto nel contesto dell'oggetto gestito (MOC). Quindi, quando l'utente preme Annulla, cerco di utilizzare NSUndoManager che appartiene al MOC.

Vorrei anche farlo usando i gruppi annidati annidati, perché potrebbero esserci gruppi nidificati.

Per verificarlo, ho scritto una semplice applicazione. L'applicazione è solo il modello "Applicazione basata su finestra" con i dati principali abilitati. Per il modello Core Data, creo una singola entità chiamata "Entity" con l'attributo intero "x". Quindi all'interno dell'applicazione applicationDidFinishLaunching, aggiungo questo codice:

- (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'idea è semplice. Prova ad inserire un nuovo oggetto Entity, annullalo, recupera tutti gli oggetti Entity nel MOC e stampali. Se tutto ha funzionato correttamente, non ci dovrebbero essere oggetti alla fine.

Tuttavia, ottengo questo output:

[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 

Come si può vedere, l'oggetto è presente nella MOC dopo cerco di annullare la sua creazione. Qualche suggerimento su cosa sto facendo male?

+0

Hi Sto avendo lo stesso problema. Hai trovato una soluzione? Hai provato a utilizzare "annulla" invece di "undoNestedGroup"? Grazie gonso – gonso

risposta

13

Il tuo problema è causato dal fatto che, a differenza di OS X, il contesto dell'oggetto gestito da iPhone non contiene un gestore di annullamento per impostazione predefinita. È necessario aggiungerne uno in modo esplicito.

Modificare il codice generato nel delegato app per la proprietà managedObjectContext a guardare come questo:

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

} 

Dopo aver effettuato questo cambiamento, il messaggio secondo registro non viene più stampato.

Speranza che aiuta ...

Dave

+2

Abbiamo appena trovato questo mentre su Google una domanda simile. Dave, sto assumendo che ci sia una buona ragione per cui undoManager è nullo di default? Ad esempio, se vado avanti e implemento questo, otterrò dei mal di testa legati alla memoria? –

4

ho provato approccio Dave, ma non ha funzionato per me. Ho finalmente trovato la soluzione nell'esempio di Apple

Il trucco è creare un nuovo contesto che condivide il coordinatore con il contesto dell'app. Per scartare le modifiche non è necessario fare nulla, basta scartare il nuovo oggetto di contesto. Poiché condividi il coordinatore, salvando gli aggiornamenti nel tuo contesto principale.

Ecco la mia versione adattata, in cui utilizzo un oggetto statico per il contesto temporaneo per creare un nuovo oggetto 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; 
} 

Spero che aiuta

Gonso

+0

Cosa succede se il tuo salvataggio fallisce? Come annulli le modifiche che sono già state inserite nel contesto e poi hai causato il fallimento? Per esempio. convalida. – malhal

0

Dovrebbe funzionare. Hai assegnato correttamente il gestore di annullamento al tuo managedObjectContext? Se hai fatto correttamente, per impostazione predefinita è annullata la registrazione abilitata e dovresti essere pronto.C'è un buon articolo sui dati di base here. C'è un buon tutorial sui dati di base e NSUndoManager here. Spero possa aiutare.

Problemi correlati