2009-08-12 17 views
67

Nel modello di dati di base dell'iPhone, Apple inserisce lo stack di dati principali nel delegato dell'app.Dove posizionare il "Core Data Stack" in un'applicazione Cocoa/Cocoa Touch

La mia inclinazione iniziale è quella di spostare questo codice nella propria classe, la cui responsabilità è gestire la gestione dello stack di dati core.

In genere incapsula questa funzionalità all'interno della sua classe o la lasci nel Delegato app?

risposta

39

Riassunto: Non v'è alcuna necessità di creare un Singleton per gestire i dati Nucleo impilare; in effetti, è probabile che ciò sia controproducente.

Lo stack di Core Data viene creato dal delegato dell'applicazione. È importante sottolineare, tuttavia, come mostrano tutti gli esempi, lo stack (principalmente il contesto dell'oggetto gestito) è non recuperato direttamente dallo stack (*). Invece, il contesto viene passato al primo controller di visualizzazione e da questi in un contesto o un oggetto gestito viene passato da un controller di visualizzazione al successivo (come descritto in Accessing the Core Data Stack). Questo segue lo schema di base per iPhone tutte le applicazioni: si passano dati o un controller modello da un controller vista al successivo.

Il ruolo tipico del singleton come descritto qui è come un controller di modello. Con Core Data, il contesto dell'oggetto gestito è già un controllore del modello. Ti dà anche la possibilità di accedere ad altre parti dello stack, se necessario. Inoltre, in alcune situazioni (come descritto nella documentazione) potresti voler utilizzare un contesto diverso per eseguire un insieme discreto di azioni. Di conseguenza, l'unità di misura appropriata per un controller di visualizzazione è di solito un contesto di oggetto gestito, altrimenti un oggetto gestito. L'uso e il passaggio di un oggetto singleton che gestisce uno stack (e dal quale si recupera un contesto) tipicamente nel migliore dei casi introduce un livello inutile di riferimento indiretto e, nel peggiore dei casi, introduce rigidità applicativa non necessaria.

(*) Non viene recuperato il contesto mediante:

[[UIApplication delegate] managedObjectContext]; 
+2

Non usare l'iniezione delle dipendenze è stato sicuramente un cattivo progetto quando ho iniziato a utilizzare i dati principali. Recentemente, prendo lo stesso approccio che hai delineato. La differenza principale è che ho inserito il codice di stack dei dati core in una categoria sul contesto NSManagedObject, se non altro per separare logicamente il codice dello stack dei dati principali da AppDelegate. In teoria, potrei usare la categoria come un singleton, ma scelgo di non farlo perché introduce "rigidità delle applicazioni" come hai detto tu. Inoltre, utilizzo un codice personalizzato per lo stack di Core Data e questo mi consente di rilasciare facilmente questo codice in nuovi progetti. –

+1

Sono con voi per l'utilizzo del Delegato app per la creazione dello stack Core Data. Sto usando un UITabBarController come controller della vista radice, e non sono sicuro di come propagare il contesto a quell'oggetto controller, poiché vive in MainWindow.xib e non sono sicuro di come assegnarlo a un ManagedObjectContext. Penso di pubblicare una domanda a parte per questo. – mvexel

+1

Quel documento Apple dice: "Quando si crea un controller di visualizzazione, si passa il contesto che dovrebbe utilizzare." ma non vedo come questo sia fatto. Il controller della vista principale viene creato tramite lo storyboard, se si utilizza uno storyboard, giusto? Quindi, come passare il contesto? –

28

Ho una classe singleton che ho lasciato fare al mio core data managment e non la lascio sul delegato dell'app. Io invece non ingombrare la classe delegato app con metodi potrei avere bisogno per conviniece come andare a prendere alcuni oggetti ecc

+1

Suoni pratico per me. Sono sorpreso che Apple includa il delegato dell'app. –

+4

probabilmente lo fanno perché vogliono mostrare come farlo e questo è come se fosse un posto comodo per metterlo dal momento che il delegato dell'app è una sorta di singleton già – Daniel

+3

con un oggetto single data controller core singleton ha perfettamente senso. lo abbiamo estratto in modo che possa essere riutilizzato in ogni progetto. +1 – stigi

11

lascio la logica dei dati di base nel delegato App per i seguenti motivi:

1) non vedo qualsiasi vantaggio reale nello spostamento di questo codice in altre classi: il concetto di delega è perfettamente soddisfatto dalla logica dei dati di base gestita dal delegato App poiché il modello di dati di base è in realtà una parte fondamentale della vostra applicazione;

2) In tutto il codice di esempio che ho visto, inclusi gli esempi di Apple, i dati di base sono gestiti dal delegato dell'app;

3) Anche nei libri di dati di base è prassi comune che il delegato dell'app gestisca il codice relativo ai dati di base;

4) Personalmente non credo che la leggibilità o qualsiasi altra cosa sia effettivamente migliorata avendo classi ad hoc per i dati di base, ma questa è una questione di gusto personale e non discuterò qui quale approccio sia il migliore. Per me, la semplicità pur mantenendo la funzionalità è importante.

+0

Di solito vedo anche lo stack di Core Data nel Delegato app. Tuttavia, il codice che guardo viene solitamente creato per scopi illustrativi. Il modo pratico per implementare qualcosa a volte differisce da tali esempi. Non volevo seguire ciecamente il codice di esempio di Apple senza una buona ragione. Tendo a pensare che tu abbia ragione nell'assumere che sarà solo una questione di gusti personali con alcuni vantaggi in entrambi i casi. –

+3

Penso anche che gli argomenti 2 e 3 siano perché in tutorial o esempi si sta cercando di minimizzare il più possibile qualsiasi codice non correlato a ciò che si sta tentando di presentare - quindi l'implementazione della meccanica di un Singleton sta aggiungendo troppo quello che dovrebbe essere un semplice esempio. La cosa che non mi piace di tenere queste cose nel Delegato app, è che aumenta il numero di cose che devono sapere sul Delegato app ... –

+0

"il concetto di delega è perfettamente soddisfatto dalla logica dei dati core gestita dal App delegato poiché il modello di dati di base è in realtà una parte fondamentale della tua applicazione; " No, l'applicazione UIA non sta delegando alcuna responsabilità per la funzionalità dei dati principali al suo delegato. È possibile decidere che un archivio persistente è un problema a livello di applicazione, ma non fa parte di UIApplicationDelegate. – quellish

10

La domanda che mi pongo, nel tuo caso, è "a chi appartiene lo stack di dati principali"? Lo stesso dato è in realtà provincia dell'applicazione, vero? (CF Core Data su Mac, in cui è possibile avere un'applicazione in grado di lavorare con più documenti alla volta, quindi lo stack Core Data appartiene a ciascun documento.)

In qualsiasi applicazione Cocoa/Cocoa Touch, il delegato dell'app. di solito è il mezzo preferito per personalizzare il comportamento dell'applicazione, quindi questo è il posto naturale per lo stack di Core Data.

Ora, il problema che ho il sospetto che stai avendo è che ci si sente sbagliato a scrivere costantemente cose come:

NSManagedObjectContext *context = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 

Quello che di solito faccio in questi casi è funzioni (non i metodi) come questo scrivere:

NSManagedObjectContext *UIAppManagedObjectContext() { 
    return [*(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; 
} 

Scrivo una funzione simile per NSPersistentStoreCoordinator e NSManagedObjectModel. Ho inserito tutti questi file nel file .h/.m del Delegato dell'app, poiché anche questi sono oggetti a livello di applicazione.

+1

Questo è divertente. Questo è esattamente il pezzo di codice che non mi piace. Non mi piace correre al Delegato app per informazioni sulla memorizzazione dei file. Sembrava "sbagliato". Questo mi ha fatto dubitare di come altri sviluppatori hanno gestito questa situazione. –

+1

Il motivo per cui il primo snippet di codice sembra sbagliato è perché ha un odore di codice. Avvolgerlo in una comoda funzione è solo deodorante. È molto più semplice passare semplicemente il contesto intorno agli oggetti che ne hanno bisogno (utilizzando l'iniezione di proprietà, principalmente). –

+2

Dovresti * non * ottenere il contesto dall'appartenenza dell'applicazione in questo modo. Dovresti passare un contesto da un controller di visualizzazione a quello successivo, come mostrato in tutti gli esempi di Apple. – mmalc

4

Sono favorevole all'idea che il delegato dell'app conosca il punto di partenza del modello e che il modello sappia dove si trova il contesto oggetto gestito. Il Core Data- "ness" del modello sembra un dettaglio di implementazione del modello per me, le classi controller (come il delegato dell'app) dovrebbero solo chiedere "dammi queste informazioni sul modello" e il modello dovrebbe sapere come rispondere quella domanda. Quindi avere un oggetto di dati di base disponibile attraverso un oggetto controller sembra un'astrazione che perde.

+0

Qualcosa che è diventato un problema nello sviluppo di iPhone è utilizzando e configurando NSFetchedResultsControllers. Puoi anche avere il tuo "Modello" ora come configurare e restituire NSFetcheResultsControllers, ma sembra che la classe del modello diventerà un po 'gonfia. Mi sento come se NSFetchedResultsControllers offuscasse la linea tra il controller e il codice del modello (non necessariamente in modo negativo). Recentemente ho preso questo e alcune altre idee nella mia nuova configurazione (aggiunta una nuova risposta). –

+0

Sono d'accordo con @Graham e questo è come lo faccio. Il tuo 'UIViewControllers' non dovrebbe avere problemi con' NSManagedObjectContext', dovrebbero solo parlare al modello e chiedere quello di cui hanno bisogno. I meccanismi per ottenere queste informazioni non sono di alcuna importanza per i miei controller di visualizzazione. – kubi

6

Lo elenco solo in una nuova risposta.(Ho scartato la mia precedente classe FJSCoreDataStack in favore di questo)

Il mio nuovo modo di gestire questo è stato quello di utilizzare una categoria su NSManagedObjectContext. Ive ha aggiunto i seguenti metodi di classe:

+ (NSManagedObjectContext *)defaultManagedObjectContext; 
+ (NSManagedObjectContext *)scratchpadManagedObjectContext; 
+ (NSManagedObjectModel *)managedObjectModel; 
+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator; 
+ (NSString *)applicationDocumentsDirectory; 

Ciò mantiene tutto dalla mia app delegato, e dà accesso Singleton devo scegliere di usarlo. Tuttavia, utilizzo ancora l'injection dependence dal Delegato app (come ha detto mmalc, introduce l'inflessibilità nel mio codice). Ho semplicemente spostato tutto il codice "Core Data Stack" nella categoria NSManagedObjectCOntext.

Mi piace passare il riferimento in giro, soprattutto perché ho un buon metodo "contesto scratchpad". Ciò mantiene flessibili i miei controller di visualizzazione poiché non li ho mai impegnati in "defaultManagedObjectContext".

rilevanti anche alla conversazione nel mondo iPhone (e può avere un impatto sulla vostra architettura): NSFetchedResultsController and constructing NSFetchRequests