2010-04-09 6 views
7

Estoy trabajando en una pieza de código para una aplicación de iPhone que obtiene un montón de datos de un servidor y construye objetos a partir de él en el cliente. Termina creando aproximadamente 40,000 objetos. No se muestran al usuario, solo necesito crear instancias de NSManagedObject y almacenarlas en el almacenamiento persistente.Manera eficiente de la memoria de insertar una matriz de objetos con Core Data

¿Me equivoco al pensar que la única forma de hacerlo es crear un solo objeto y luego guardar el contexto? ¿es mejor crear los objetos a la vez y luego guardarlos en el contexto una vez que se hayan creado y guardado en algún conjunto o matriz? Si es así, ¿puede uno mostrar algún código de ejemplo de cómo se hace esto o apuntarme en la dirección del código donde se hace?

Los objetos en sí mismos son modelos relativamente sencillos con atributos de cadena o enteros y no contienen ninguna relación compleja.

Respuesta

5

En cualquier caso, no guarde después de insertar cada objeto, o prepárese para actuaciones terribles.

Aquí está el código que utilizo para rellenar un repositorio de Core Data en el primer lanzamiento.

#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]; 
} 

Tampoco se olvide de guardar una última vez después del bucle.

También tenga en cuenta que existe un error que dará lugar a un accidente si las tres condiciones siguientes:

  1. El repositorio está vacío
  2. Usted tiene una UITableView con secciones
  3. Su la primera guarda guarda más de un objeto.

La solución en el código anterior es para inicializar el numUnsavedAirports a MAX_UNSAVED_AIRPORTS_BEFORE_SAVE con el fin de asegurarse de que el primer salvamento sucede después de la primera inserción.

Espero que esto ayude.

1

Probablemente sea mejor crear un solo objeto y guardar el contexto.

Tiene 40k objetos. Digamos que crear un solo NSManagedObject requiere x unidades de tiempo. Las unidades de 40kx de tiempo probablemente sean medibles. Mientras se produce la creación del objeto, el usuario puede salir de la aplicación por alguna razón; los usuarios son impredecibles La próxima vez que inicie su aplicación, volverá a realizar el proceso. No sería deseable crear el objeto 39,999.º solo para que el usuario salga de la aplicación y pierda todo ese trabajo.

Si su aplicación creara cada objeto y lo guardara, podría acelerar un poco este proceso. La aplicación se inicia y comprueba si pudo completar la tarea la última vez que se ejecutó. Si la tarea estaba incompleta, podría intentar retomarla donde quedó.

El método de creación y guardado de objetos únicos puede tardar más en completarse, pero tendrá una mayor probabilidad de completar la tarea.

En términos de consumo de memoria, esto también minimiza el estado de memoria de su aplicación. El contexto no rastrea 40k objetos en la memoria.

+2

Guardar cada objeto individualmente producirá un rendimiento terrible. –

3

Guardar después de cada objeto produciría muy mal rendimiento. Debería tener un saldo de los ahorros quizás cada 100 (las pruebas determinarán el punto óptimo) y luego realizar un seguimiento de dónde se encuentra en el procesamiento cuando el usuario se cierra.

Tiene tiempo de salida para almacenar el estado para que pueda almacenar fácilmente su posición en el procesamiento de datos (5 bloques de 100 guardados) y volver a realizar la copia de seguridad desde donde lo dejó.

Guardar cada objeto individualmente martilleará el disco y ralentizará la aplicación.

+0

Además de este consejo correcto, también debería considerar reiniciar ManagedObjectContext después de guardar para reducir la huella de memoria. Pero ten en cuenta que restablecer el contexto te hace perder resultados intermedios en ese contexto. P.ej. los fetchResults por lotes también se han ido. – Bjinse

+0

Los documentos de Apple relevantes están aquí: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html – Bjinse

Cuestiones relacionadas