45

Ho un'interfaccia utente per inserire una transazione. una volta che l'utente fa clic su un plus, ottiene lo schermo e voglio istanziare la mia entità Core Data NSManagedObject permettendo all'utente di lavorarci sopra. Quindi, quando l'utente fa clic sul pulsante Salva, chiamerò la funzione di salvataggio.C'è un modo per istanziare un NSManagedObject senza inserirlo?

così giù per codice:

transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext]; 
//even if i dont call save: its going to show up on my table 
[self.managedObjectContext save:&error] 

P.S Se si utilizza una NSFetchedResultsController su quel tavolo e vedere che il NSFetchedResultsController sta inserendo una sezione e un oggetto alla tabella.

Il mio pensiero è se c'è un modo per istanziare la transazione NSManagedObject potrei aggiornarlo senza salvare fino a che il client non sceglie.

risposta

16

C'è un problema fondamentale con l'utilizzo di un MOC nullo: gli oggetti in diversi MOC non si riferiscono tra loro — questo presumibilmente si applica anche quando un lato di una relazione ha un MOC nullo. Cosa succede se salvi? (Cosa succede quando viene salvata un'altra parte della tua app?)

Se il tuo oggetto non ha relazioni, allora ci sono molte cose che puoi fare (come NSCoding).

Potrebbe essere possibile utilizzare -[NSManagedObject isInserted] in NSPredicate (presumibilmente si tratta di SI tra inserimento e salvataggio).In alternativa, è possibile utilizzare una proprietà temporanea con lo stesso comportamento (impostarla su SÌ in awakeFromInsert e NO su willSave). Entrambi possono essere problematici se viene salvata una parte diversa della tua app.

Utilizzare un secondo MOC è come utilizzare "CoreData", tuttavia; gestisce automaticamente il rilevamento e la risoluzione dei conflitti. Ovviamente, non vuoi creare un nuovo MOC ogni volta che c'è un cambiamento; potrebbe essere vagamente ragionevole avere un MOC per le modifiche non salvate dal "thread utente" lento se non vi dispiace che alcune parti dell'interfaccia utente vedano cambiamenti non salvati in altre parti (il sovraccarico della comunicazione tra i MOC è trascurabile).

+0

Ciao @tc. Ho provato la prima risposta che è quella di inserireIntoManagedObjectContext: nil, ma poi quando ho voluto assegnare una relazione l'app si è bloccata con errore: motivo: 'Tentativo illegale di stabilire una' categoria 'di relazione tra oggetti in diversi contesti. quindi credo che la mia domanda è che non è legale creare una relazione tra un oggetto NSManaged di contesto e un oggetto gestito fuori contesto, quale sarebbe la soluzione? –

+0

Ho finito per creare un'entità di categoria allo stesso modo senza contesto, ma quando si trattava di salvare ho aggiunto entrambi al contesto e poi ha funzionato bene. –

+2

Posso attestare la correttezza di questa risposta.Sono appena stato morso da un problema relativo al contesto nullo di un oggetto. I valori di attributo assegnati all'oggetto prima di aggiungerlo a un contesto non si propagano al contesto padre quando alla fine l'oggetto viene aggiunto al contesto figlio. Gli attributi sono memorizzati come 'nil' nell'archivio di persistenza. Quando ho cambiato l'ordine (cioè assegnare i valori degli attributi dopo averlo inserito in un contesto), le cose hanno funzionato correttamente. Morale della trama è, non è una buona idea istanziare un oggetto senza un contesto. –

8

È possibile inserire uno con -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:], passando nil per il contesto dell'oggetto gestito. Ovviamente, è necessario assegnarlo a un contesto (utilizzando -[NSManageObjectContext insertObject:] prima di salvare, tuttavia, per quanto ne so, non è proprio lo schema previsto in Core Data, tuttavia (vedi la risposta di @ mzarra here). problemi (ad esempio assicurandosi che l'istanza venga assegnata a un contesto prima che si aspetti di averne uno, ecc.) Lo schema più standard consiste nel creare un nuovo contesto di oggetto gestito e inserire il nuovo oggetto in quel contesto. il contesto e gestisci il NSManagedObjectDidSaveNotification per unire le modifiche nel tuo contesto "principale" Se l'utente annulla la transazione, devi solo spazzare via il contesto e andare avanti con la tua attività

+0

Credo che si intende 'NSManagedObject', non' NSManagedObjectContext'. Ad ogni modo, non sembra che tu possa modificare il MOC a NSManagedObject associato a — potresti confonderlo con '- [NSManagedObjectContext assignObject: toPersistentStore:]'. –

+0

@ tc, grazie per la cattura degli errori di battitura. –

30

Per quello che vale, Marcus Zarra sembra promuovere l'approccio contestuale nil, sostenendo che è costoso creare un nuovo contesto. ls, vedi this answer a una domanda simile.

Aggiornamento

Attualmente sto usando l'approccio contesto nullo e ho incontrato qualcosa che potrebbe essere di interesse per gli altri. Per creare un oggetto gestito senza un contesto, utilizzare il metodo initWithEntity:insertIntoManagedObjectContext: di NSManagedObject. Secondo la documentazione di Apple per questo metodo:

If context is not nil , this method invokes [context insertObject:self] (which causes awakeFromInsert to be invoked).

L'implicazione qui è importante. L'utilizzo di un contesto nil durante la creazione di un oggetto gestito impedirà di chiamare insertObject: e pertanto impedirà il richiamo di awakeFromInsert. Di conseguenza, qualsiasi inizializzazione dell'oggetto o impostazione dei valori di proprietà predefiniti eseguita in awakeFromInsert non avverrà automaticamente quando si utilizza un contesto nil.

Bottom line: quando si utilizza un oggetto gestito senza contesto, awakeFromInsert non verrà chiamato automaticamente e potrebbe essere necessario un codice aggiuntivo per compensare.

+0

Ciao questo ha funzionato per un po 'fino a quando ho provato a stabilire una relazione tra la mia transazione e una categoria NSManagedObject. poi l'app si è bloccata a causa di ciò. C'è un modo per aggirarlo? –

+0

Se è necessario impostare relazioni, sceglierei l'approccio contestuale. Come tc sottolinea, non si suppone che gli oggetti in contesti diversi facciano riferimento l'un l'altro. D'altra parte, potresti posticipare l'impostazione di tali relazioni finché * dopo * non inserisci il nuovo oggetto non associato nel tuo contesto principale. –

17

ecco come ho lavorato fuori:

Su di carico, dove sappiamo che si tratta di una nuova operazione, ho creato un fuori contesto uno.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext]; 
     transaction = (Transaction *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

poi, quando si è trattato di stabilire una nave di relazione ho fatto questo:

if(transaction.managedObjectContext == nil){ 
     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext]; 
     Category *category = (Category *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 
     category.title = ((Category *)obj).title; 
     transaction.category = category; 
     [category release]; 
    } 
    else { 
     transaction.category = (Category *)obj; 
    } 

e alla fine per salvare:

if (transaction.managedObjectContext == nil) { 
     [self.managedObjectContext insertObject:transaction.category]; 
     [self.managedObjectContext insertObject:transaction]; 
    } 
    //NSLog(@"\n saving transaction\n%@", self.transaction); 

    NSError *error; 
    if (![self.managedObjectContext save:&error]) { 
     // Update to handle the error appropriately. 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
     exit(-1); // Fail 
    } 
+0

Mi chiedevo se potevo fare ... transaction = (Transaction *) [NSEntityDescription insertNewObjectForEntityForName: @ "Transaction" inManagedObjectContext: context]; e quindi transaction.managedObjectContext = nil; sarebbe sbagliato? – yunas

2

Un NSManagedObject possono essere creati usando il nil come il contesto, ma se esiste un altro NSManagedObjects a cui deve collegarsi, si verificherà un errore. Il modo in cui lo faccio Passo il contesto nella schermata di destinazione e creo un NSManagedObject in quello schermo. Apportare tutte le modifiche al collegamento di altri NSManagedObjects. Se l'utente tocca il pulsante Annulla, elimino NSManagedObject e salvi il contesto. Se l'utente tocca il pulsante Salva, aggiorno i dati in NSManagedObject, salvalo nel contesto e rilascia lo schermo. Nella schermata di origine aggiorno la tabella con una ricarica.

L'eliminazione di NSManagedObject nella schermata di destinazione consente ai dati di base di aggiornare il file. Questo di solito è il tempo sufficiente per non vedere il cambiamento nel tableview. Nell'app Calendario per iPhone si ha un ritardo dal momento in cui viene salvato al momento in cui viene visualizzato nella vista tabella. Questo potrebbe essere considerato un aspetto positivo dal punto di vista dell'interfaccia utente che l'utente si concentrerà sulla riga appena aggiunta. Spero che aiuti.

-3
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:nil]; 

se l'ultimo parametro è pari a zero, verrà restituito un NSManagedObject, senza risparmiare al db

+0

Ciò causerà un errore: *** Termina l'applicazione a causa dell'eccezione non rilevata 'NSInvalidArgumentException', motivo: '+ entityForName: nil non è un parametro NSManagedObjectContext legale che cerca il nome dell'entità ... – c9s

Problemi correlati