2 votes

Comment ajouter correctement un grand ensemble de données dans CoreData ?

J'ai un énorme NSArray (4.000.000 objets) que je veux sauvegarder dans Core Data. Comme j'utilise ARC et que le pool de libération automatique peut devenir trop grand, j'ai divisé le processus en plusieurs boucles (pour que les pools de libération automatique aient la possibilité de se vider d'eux-mêmes).

Dans le code suivant, j'utilise un gestionnaire (clMan) pour ajouter des éléments des dictionnaires dans le tableau (régions). Les dictionnaires contiennent deux champs de type chaîne qui sont analysés en entiers scalaires.

Code de partitionnement des données en plusieurs boucles

int loopSize = 50000;
int loops = 0;
int totalRepetitions = regions.count;
loops = totalRepetitions / loopSize;
int remaining = totalRepetitions % loopSize;

loops += 1;

for (int i = 0; i < loops; i++) {

    int k = 0;
    if (i == 0) k = 1;

    if (i == (loops - 1))
    {
            // Last loop

            for (long j = i * loopSize + k; j < i * loopSize + remaining; j++) {
                [clMan addItemWithData:[regions objectAtIndex:j]];
            }
            [clMan saveContext];
            break;

    }

    // Complete loops before the last one
        for (long j = i * loopSize + k; j < (i + 1) * loopSize; j++) {
            [clMan addItemWithData:[regions objectAtIndex:j]];
        }
        [clMan saveContext];
        NSLog(@"Records added : %d", i * loopSize);

}
NSLog(@"Finished adding into core data");

Code pour l'ajout des données dans les données de base :

-(void)addItemWithData:(NSDictionary *)data
{

    MyRegion *region = [NSEntityDescription
                                              insertNewObjectForEntityForName:@"MyRegion"
                                              inManagedObjectContext:self.context];

    region.index = [((NSString *)[data objectForKey:REGION_INDEX]) intValue];
    region.id = [((NSString *)[data objectForKey:REGION_ID]) intValue];

} 

Le programme se bloque lorsqu'il atteint l'indice 1 500 000. Le plantage ne semble pas être dû à des problèmes d'analyse ou de logique.

Quelqu'un peut-il me dire si ma logique est mauvaise ou quelle est la bonne façon d'ajouter cette quantité de données dans CoreData ?

3voto

Michael Rose Points 6164

Après chaque boucle, essayez d'appeler NSManagedObjectContext.reset pour "oublier" les copies locales dans le MOC. Dans le cas contraire, celles-ci pourraient ne pas être effacées et causer un problème.

Les exemples de code WWDC 2012 sur iCloud ont une méthode appelée seedStore où l'on migre une base de données SQL locale vers celle d'iCloud - en utilisant une taille de lot de 5 000 enregistrements :

if (0 == (i % batchSize)) {
    success = [moc save:&localError];
    if (success) {
        /*
           Reset the managed object context to free the memory for the inserted objects
           The faulting array used for the fetch request will automatically free
           objects with each batch, but inserted objects remain in the managed
           object context for the lifecycle of the context
         */
        [moc reset];
    } else {
        NSLog(@"Error saving during seed: %@", localError);
        break;
    }
}

(Ici i est l'indice actuel du lot, donc i % batchSize == 0 si nous commençons un nouveau lot)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X