2010-07-10 8 views
1

J'utilise CoreData (avec SQLite comme magasin) dans une application iPhone iOS 4 pour stocker les données que je récupère initialement à partir d'un fichier xml. Mon modèle de données contient plus de 15 entités et je suis préoccupé par la consommation de mémoire depuis que j'ai vu CoreData créer tous les NSManagedObject en mémoire pour représenter le graphe d'objet de mon modèle de données. J'analyse le fichier xml avec un analyseur syntaxique basé sur SAX libxml2 et j'essaie de stocker chaque 'ensemble aggloméré' d'entités par segments, mais je souhaite libérer chaque managedobject après l'insertion de cet agglomérat et la sauvegarde du contexte géré, dans afin d'économiser de la mémoire pour le prochain agglomérat. J'ai vu que je devais utiliser refreshObject: mergeChanges: pour contrebalancer la rétention multiple que chaque objet a reçu en étant associé à d'autres par des relations (comme prévu dans le modèle de données). Je fais cela après avoir sauvegardé le contexte, mais ensuite quand j'essaie de chercher à nouveau dans le magasin en essayant d'aller chercher ce que j'ai inséré avant de ne rien retourner. Ai-je raté quelque chose?CoreData: Releasing ManagedObject

Répondre

2

Si tout ce que vous faites est d'importer (par exemple, vous n'avez pas besoin de garder les objets insérés pour afficher à l'utilisateur et ainsi de suite), vous pouvez simplement utiliser [moc reset] après la sauvegarde. Donc, l'algorithme ressemblerait à quelque chose comme ceci:

NSManagedObjectContext* moc = ...; 
while ([xmlData hasMoreObjects]) { 
    // Create e.g. 500 objects and insert them into the managed object context 
    NSError* error = nil; 
    if (![moc save:&error]) { 
     // handle the error 
    } 
    [moc reset]; // Here the inserted objects get released in the core data stack 
} 

Remise à zéro du contexte de l'objet géré fait la même chose que si vous rafraichir tous les objets (comme précédemment). Vous devriez également envisager d'utiliser le [[NSManagedObject alloc] initWithEntity:insertIntoManagedObjectContext:] au lieu des méthodes pratiques sur NSEntityDescription, car vous pouvez les libérer juste après que vous n'en ayez plus besoin, et ils ne resteront pas en mémoire jusqu'à ce que le pool autorelease soit effacé. Jetez un coup d'œil au Guide de programmation des données de base, car il contient une section entière centrée sur l'importation efficace de données et une autre sur la gestion de la mémoire avec les données de base.

+0

merci j'essaierai [moc reset].Atm J'utilise NSEntityDescription entityForName: inManagedObjectContext: puis initWithEntity: insertIntoManagedObjectContext pour créer un NSManagedObject mais il semble que je ne puisse pas le libérer complètement (après l'initWithEntity il a un compteur de retenue de 2) – rano

+0

Je suppose que ce n'est pas 1 puisqu'ils sont insérés dans le contexte qui les retient (même si je mets setRetainsRegisteredObjects: NO). – rano

+0

Vous ne devriez pas compter sur le nombre de retenue, c'est une façon très inexacte de déterminer si vous fuyez un objet. Si vous effectuez une réinitialisation, les données de base lâcheront vos données (la plupart du temps, il y a encore des données dans le cache des lignes, etc.). Essayez de trouver des fuites à l'aide d'instruments. C'est un excellent outil pour voir où votre mémoire disparaît, et où optimiser. – Alfonso

0

Je pense que vous devez le faire pour chaque changement

NSManagedObjectContext *moc; 
NSError *error; 
[moc save:&error]; 

Sinon, il sera mis au rebut

+0

Je le fais en effet. Après cela, j'appelle refreshObject: mergeChanges: et essaye de libérer les objets nsmanaged. Plus tard j'essaie d'aller chercher du contexte mais rien ne semble être stocké – rano

1

Vous ne pouvez pas gérer directement/manuellement la mémoire des objets gérés, car le contexte contrôle le cycle de vie des objets pour maintenir l'intégrité des graphes.

Si vous pouvez traiter l'importation en morceaux discrets, enregistrez le contexte après chaque morceau suivi par:

[context refreshObject:theObject mergeChanges:NO] 

... qui convertit les objets nouvellement enregistrés en défauts afin qu'ils prennent très peu de mémoire.

Vous avez uniquement besoin d'erreurs pour définir les relations afin que les objets traités dans le bloc précédent restent disponibles pour définir des relations dans le bloc en cours. Dans la mesure du possible, je crée des objets en un seul passage, les sauvegarde, les convertit en défauts et les définit ensuite lors de la passe suivante. Ce n'est pas toujours pratique si vous avez des relations requises.

Vous pouvez consulter le Guide de programmation des données de base: Efficiently Importing Data si vous ne l'avez pas déjà fait.