L'app a volte inserisce oggetti nel contesto dell'oggetto gestito che non devono essere necessariamente salvati. Ad esempio, quando lancio una modal 'Aggiungi entità', creo un oggetto gestito e lo assegno alla modale. Se l'utente salva da quella modale, salvo il contesto. Se cancella, cancello l'oggetto e non è necessario salvare.Implementazione corretta di genitore/figlio NSManagedObjectContext
Ora ho introdotto una funzione di "importazione" che passa alla mia app (utilizzando uno schema URL) e aggiunge un'entità. Poiché una di queste modali potrebbe essere aperta, non è sicuro salvare il contesto a questo punto. L'oggetto temporaneo creato per il modale verrà salvato, anche se l'utente annulla, e non vi è alcuna garanzia che l'eliminazione (dall'operazione di annullamento) verrà salvata in un secondo momento - l'utente potrebbe uscire dall'app.
Analogamente, non posso semplicemente salvare ogni volta che la mia app si chiude. Se la modale è aperta in quel punto, l'oggetto temporaneo verrà salvato in modo errato.
Per risolvere questo problema, sto tentando di utilizzare un contesto figlio, come illustrato in here. Dopo aver letto tutto quello che ho potuto trovare su SO, ho davanzale avere un paio di domande:
Quale tipo di concorrenza dovrei utilizzare per ogni contesto? Ricorda che non sto facendo questo per i vantaggi di prestazioni/threading. So che non posso usare NSConfinementConcurrencyType per il contesto principale se deve avere contesti secondari, ma non sono sicuro di quale delle altre due opzioni sia più adatta. Per il contesto del bambino, ha bisogno di corrispondere? O posso usare anche il tipo di confinamento qui? Ho provato una varietà di combinazioni e tutto sembra funzionare bene, ma mi piacerebbe sapere quale è appropriato per le mie esigenze.
(side issue) Perché posso farlo funzionare solo se utilizzo un iVar di classe? Ho pensato che dovrei essere in grado di dichiarare il contesto temporaneo nel metodo in cui è stato creato e in seguito fare riferimento ad esso usando entity.managedObjectContext. Ma sembra essere nulla prima che io venga ad accedervi? Questo è corretto se invece utilizzo un iVar per mantenere il riferimento.
Qual è il modo corretto o di propagare la modifica al contesto principale? Ho visto vari commenti utilizzando diverse implementazioni bloccate a blocchi su ciascuno dei contesti. Dipende dal mio tipo di concorrenza? La mia versione attuale è:
//save the new entity in the temporary context NSError *error = nil; if (![myObject.managedObjectContext save:&error]) {NSLog(@"Error - unable to save new object in its (temporary) context");} //propogate the save to the main context [self.mainContext performBlock:^{ NSError *error2 = nil; if (![self.mainContext save:&error2]) {NSLog(@"Error - unable to merge new entity into main context");} }];
Quando il mio utente salva, invia il suo delegato (il mio principale controller di vista) un messaggio. Il delegato riceve l'oggetto che è stato aggiunto e deve individuare lo stesso oggetto nel contesto principale. Ma quando lo cerco nel contesto principale, non viene trovato. Il contesto principale contiene contiene l'entità - Posso registrare i suoi dettagli e confermare che è lì - ma l'indirizzo è diverso? Se questo dovrebbe accadere (perché?), Come posso individuare l'oggetto aggiunto nel contesto principale dopo il salvataggio?
Grazie per qualsiasi intuizione. Ci scusiamo per una lunga domanda in più parti, ma ho pensato che qualcuno avrebbe probabilmente affrontato tutti questi problemi in precedenza.
Sulla base della risposta di Andy sopra, ho testato una versione senza utilizzare i blocchi per il salvataggio e finora funziona (per non dire che è corretta). Qual è lo scopo di utilizzare l'implementazione del blocco e quali problemi potrebbero sorgere se continuo a chiamare semplicemente save nei contesti? –
Per quanto riguarda il n. 2, che suppongo non dovrebbe appartenere alla domanda in realtà - ho ancora un riferimento valido al mio oggetto inserito - non mantiene il suo moc vivo? –
Come ho già detto al punto 3, lo scopo dell'utilizzo dei metodi basati su blocchi è quello di garantire che i messaggi vengano inviati ai thread corretti. Questo è davvero importante solo se stai facendo un lavoro con i dati core multithread. Per inciso, puoi usare anche performBlock per lavorare in modo asincrono (se il MOC è su un thread diverso. Chiamare performBlock su un MOC sul thread principale invia solo il codice al thread principale) – jmstone617