2010-04-09 13 views
7

Sto lavorando a un pezzo di codice per un'applicazione iPhone che recupera un gruppo di dati da un server e crea oggetti da esso sul client. Finisce per creare circa 40.000 oggetti. Non vengono visualizzati per l'utente, ho solo bisogno di creare istanze di NSManagedObject e archiviarli in memoria persistente.Modo memoria efficiente di inserire una matrice di oggetti con Core Data

Mi sbaglio nel pensare che l'unico modo per farlo è creare un singolo oggetto, quindi salvare il contesto? è meglio creare gli oggetti tutti in una volta, quindi in qualche modo salvarli nel contesto dopo che sono stati creati e memorizzati in alcuni set o array? In tal caso, si può mostrare un codice di esempio per come è fatto o indicarmi la direzione per codificare dove è fatto?

Gli oggetti stessi sono modelli relativamente semplici con attributi stringa o intero e non contengono relazioni complesse.

risposta

5

In ogni caso, non salvare dopo aver inserito ogni oggetto o essere preparati per prestazioni spaventose.

Ecco il codice che utilizzo per popolare un repository Core Data al primo avvio.

#define MAX_UNSAVED_AIRPORTS_BEFORE_SAVE 1000 
int numAirports = 0; 
int numUnsavedAirports = MAX_UNSAVED_AIRPORTS_BEFORE_SAVE; // *** bug. see below 
for (NSDictionary *anAirport in initialAirports) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    Airport *newAirport = [NSEntityDescription insertNewObjectForEntityForName:@"Airport" inManagedObjectContext:managedObjectContext]; 

    newAirport.city   = [anAirport objectForKey:@"city"]; 
    newAirport.code   = [anAirport objectForKey:@"code"]; 
    newAirport.name   = [anAirport objectForKey:@"name"]; 
    newAirport.country_name = [anAirport objectForKey:@"country_name"]; 
    newAirport.latitude  = [NSNumber numberWithDouble:[[anAirport objectForKey:@"latitude"] doubleValue]]; 
    newAirport.longitude = [NSNumber numberWithDouble:[[anAirport objectForKey:@"longitude"] doubleValue]]; 
    newAirport.altitude  = [NSNumber numberWithDouble:[[anAirport objectForKey:@"altitude"] doubleValue]]; 

    numAirports++; 
    numUnsavedAirports++; 
    if (numUnsavedAirports >= MAX_UNSAVED_AIRPORTS_BEFORE_SAVE) { 
     if (![managedObjectContext save:&error]) { 
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
      abort(); 
     } 
     numUnsavedAirports = 0; 
    } 
    [pool release]; 
} 

Inoltre, non dimenticare di salvare un'ultima volta dopo il ciclo.

essere consapevoli che esiste un errore che porterà ad un incidente, se tutte e tre le seguenti condizioni sono soddisfatte anche:

  1. il repository è vuoto
  2. Hai un UITableView con sezioni
  3. tuo prima salva salva più di un oggetto.

La soluzione nel codice sopra è per inizializzare il numUnsavedAirports a MAX_UNSAVED_AIRPORTS_BEFORE_SAVE al fine di assicurarsi che il primo salvataggio avviene dopo il primo inserto .

Spero che questo aiuti.

1

Probabilmente è meglio creare un singolo oggetto e salvare il contesto.

Hai 40k oggetti. Diciamo che la creazione di un singolo NSManagedObject richiede x unità di tempo. Le unità di tempo 40kx sono probabilmente misurabili. Mentre la creazione dell'oggetto sta accadendo, l'utente potrebbe chiudere l'app per qualche motivo; gli utenti sono imprevedibili. La prossima volta che la tua app verrà avviata, ripercorrerai tutto il processo. Non sarebbe desiderabile creare l'oggetto 39.999th solo per far sì che l'utente lasciasse l'app e perdesse tutto quel lavoro.

Se la tua app dovesse creare ogni oggetto e salvare, potresti accelerare un po 'questo processo. L'app si avvia e verifica se è stata in grado di completare l'attività l'ultima volta che è stata eseguita. Se l'attività era incompleta, potrebbe provare a riprendere da dove era stata interrotta.

Il metodo di creazione e salvataggio dell'oggetto singolo può richiedere più tempo per essere completato, ma avrà una maggiore probabilità di completamento dell'attività.

In termini di consumo di memoria, anche questo riduce al minimo lo stato di memoria della vostra app. Il contesto non sta rintracciando oggetti 40k in memoria.

+2

Il salvataggio di ogni oggetto singolarmente produrrà prestazioni terribili. –

3

Il salvataggio dopo ogni oggetto produrrebbe prestazioni pessime. Dovresti avere un saldo dei salvataggi, forse ogni 100 (il test determinerà il punto debole) e quindi tenere traccia di dove ti trovi nel processo quando l'utente si chiude.

Si ottiene l'ora di uscita per memorizzare lo stato in modo da poter memorizzare facilmente la posizione nell'elaborazione dei dati (5 blocchi di 100 salvati) e riprendere da dove si era interrotto.

Il salvataggio di ogni oggetto individualmente causerebbe il martellamento del disco e rallenterebbe l'app.

+0

Oltre a questo consiglio corretto, è necessario prendere in considerazione anche il reset di ManagedObjectContext dopo il salvataggio per ridurre il footprint di memoria. Ma fai attenzione che reimpostare il contesto ti fa perdere qualsiasi risultato intermedio in quel contesto. Per esempio. i risultati di recupero in batch sono spariti. – Bjinse

+0

I documenti Apple rilevanti sono qui: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html – Bjinse

Problemi correlati