[Core data] est-ce que la stack core data retain les NSManagedObject ?

colas_colas_ Membre
juin 2015 modifié dans Objective-C, Swift, C, C++ #1

Hello,


 


Une question relative à  Core Data me trotte dans la tête depuis à  un moment.


 


Imaginons que 


a) je crée un NSManagedObject


ou b ) je "fetche" un NSManagedObject


 


Est-ce cet objet va être retained par un des objets de la stack Core Data ? 


 


D'un côté, j'imagine que oui. Car si on n'a pas fait de save sur le context, je trouverai ça louche que l'object puisse disparaà®tre avant d'avoir été sauvé (mais pourquoi pas).


 


D'un autre côté,  j'imagine que non, parce que sinon ça ferait des leaks.


 


 


 


Si quelqu'un le sait, ça m'intéresserait !


 


Merci


Colas


Réponses

  • CéroceCéroce Membre, Modérateur

    La gestion de la mémoire avec Core Data n'est pas précisée par la doc hormis "Core Data gère la mémoire des objets lui-même".


    Ce que je peux te dire par expérience, c'est qu'un Managed Object peut disparaà®tre de la mémoire.


     




    D'un côté, j'imagine que oui. Car si on n'a pas fait de save sur le context, je trouverai ça louche que l'object puisse disparaà®tre avant d'avoir été sauvé (mais pourquoi pas).




    Un NSManagedObject est une représentation objet de l'entité correspondante. Les modifications apportées à  l'entité peuvent très bien avoir été mémorisées par le MOC, même si on n'a pas de NSManagedObject correspondant en mémoire.


  • Merci pour ces précisions. 


     




    Un NSManagedObject est une représentation objet de l'entité correspondante. Les modifications apportées à  l'entité peuvent très bien avoir été mémorisées par le MOC, même si on n'a pas de NSManagedObject correspondant en mémoire.




     


    C'est ce que je voulais dire par "(mais pourquoi pas)".


  • AliGatorAliGator Membre, Modérateur
    La relation parent->enfant est dans le sens MOC->MO

    Autrement dit, les NSManagedObjectsContexts "retain" leurs NSManagedObjects, mais les NSManagedObjects ne retiennent pas leur NSManagedObjectContexts.

    je trouverai ça louche que l'object puisse disparaà®tre avant d'avoir été sauvé.

    Du coup non l'objet que tu as créé ne peut pas disparaà®tre... tant que tu gardes une référence strong sur le MOC dans lequel il a été créé, donc ça ne pose pas de problème.

    Si tu crées un MOC, puis crées une ou plusieurs entités dans ce MOC, tant que tu gardes une référence strong sur le MOC les entités créées continueront d'exister, même si tu n'as pas gardé de propriété strong dessus. Ensuite, si tu save le MOC (sur son MOC parent ou sur le PersistentStore), les objets seront donc sauvés et tu pourras relâcher ta référence forte sur le MOC pour l'oublier. Si tu relâches ta référence forte sur ton MOC sans avoir fait "save", tes objets créés dedans depuis sa création seront perdus.

    C'est un peu comme GIT et ses branches (d'ailleurs je fais souvent le parallèle dans ma tête). Pour moi un MOC c'est un peu comme une branche GIT, le PersistentStore étant la branche "master", et les ManagedObject était les commits. Tu peux créer une branche qui dérive de master (créer un nouveau MOC dont le parent est le PersistentStore), rajouter des commits dessus (créer des objets dans ce MOC), et ensuite, quand tu merge ta branche dans master (tu fais "save" sur ton MOC) et tes commits sont sauvés. Si jamais tu ne merges pas ta branche dans master et que tu la delete sans la merger (que tu remet ta référence forte vers ton MOC à  nil et ne le retient plus et qu'il est "released"), tous les commits de cette branche (les ManagedObjects créés dans ce MOC depuis sa création) seront perdus à  jamais car ils n'auront jamais été mergés dans master et qu'ils n'auront plus aucune autre branche qui pointe vers eux.


    C'est d'ailleurs pour cela qu'il ne faut jamais stocker par exemple dans un tableau des NSManagedObject si tu ne retiens pas aussi leur MOC. Par exemple si tu imagines créer des ManagedObject dans un MOC, puis passer ce tableau de NSManagedObjects à  un autre objet (par exemple à  ton service qui gère l'appel d'un WebService avec ces objets en paramètre), tu n'as pas de garantie que le MOC ne sera pas détruit entre temps et que tes ManagedObjects ne seront pas à  trainer dans le vite (et tu risques de te retrouver avec des NSManagedObject qui sont retenus par ton NSArray, mais qui ne sont plus rattachés à  aucun MOC puisque ce dernier a été détruit entre temps, et du coup plantage si tu essayes d'utiliser ces pointeurs vers tes ManagedObject alors qu'ils n'existent plus)
    Evite donc d'avoir des références "strong" vers des NSManagedObject, car tu risques alors de les garder en mémoire plus longtemps que leur MOC et si ça arrive et qu'ils deviennent invalides c'est aussi mauvais qu'un crash type EXC_BADACCESS. (Sauf si jamais tu as aussi une référence strong vers leur NSManagedObjectContext dans lequel ils ont été créés, et du coup là  ils ne risquent pas de disparaà®tre tant que le MOC est aussi retenu)
  • Merci @Ali pour ta réponse. Du coup ça vient en contradiction avec ce que dit @Céroce.


     


     




    C'est d'ailleurs pour cela qu'il ne faut jamais stocker par exemple dans un tableau des NSManagedObject si tu ne retiens pas aussi leur MOC. Par exemple si tu imagines créer des ManagedObject dans un MOC, puis passer ce tableau de NSManagedObjects à  un autre objet (par exemple à  ton service qui gère l'appel d'un WebService avec ces objets en paramètre), tu n'as pas de garantie que le MOC ne sera pas détruit entre temps et que tes ManagedObjects ne seront pas à  trainer dans le vite (et tu risques de te retrouver avec des NSManagedObject qui sont retenus par ton NSArray, mais qui ne sont plus rattachés à  aucun MOC puisque ce dernier a été détruit entre temps, et du coup plantage si tu essayes d'utiliser ces pointeurs vers tes ManagedObject alors qu'ils n'existent plus)




     


    Tu dis qu'ils n'existent plus (dernière ligne) alors qu'ils sont retain par le tableau. C'est contradictoire. Du coup, qu'entends-tu par ils "n'existent plus" ? Qu'ils sont invalides ? ça va déboucher sur quelle erreur ?


     


    Ton explication permet de bien comprendre pourquoi les NSManagedObject ne traversent pas les MOC. On passe un MO d'un MOC à  un autre par son objectID.


     


    Pour changer un peu de sujet, j'ai pris l'habitude de mettre toutes mes références à  strong sauf pour les delegate ou les liens "enfant -> parent". 


     


    Dans mon cas, je n'ai qu'un moc et il est retain par mon singleton dataManager. Or un singleton n'est jamais release (je sais plus pourquoi). Donc, c'est ok.


  • Du coup, je pense que j'ai une fuite mémoire puisque je fetch des MO pour récupérer des NSData que j'utilise ensuite. J'imagine donc que dans mon cas, les NSData s'accumulent. Il faudrait que je crée un MOC fils pour fetcher mes data.


    ça fait une utilisation des MOC parent/fils que je ne connaissais pas. Pour moi, il ne s'agissait que d'optimisation (dispat_async et compagnie).
  • FKDEVFKDEV Membre
    juin 2015 modifié #7

    En fait, le MOC ne retient ses managed object que s'ils ont été modifiés et en attendant le save.


    Autrement dit les managed objects retournés par un fetch ne sont pas retenus et heureusement sinon, on ne pourrait pas libérer ces objects sans libérer le MOC. Ce qui ne correspond pas à  la stack par défaut d'Apple qui propose un seul MOC principal.


     


    Par contre, on peut faire en sorte que le MOC garde des références vers ses objets en appelant setRetainsRegisteredObjects.


    Pratique si on utilise des MOC temporaires pour faire des requêtes.


     


    Lire les premiers paragraphes de cette doc.


  • @fkdev Merci pour le lien qui clarifie tout. Il répond même à  ma question suivante sur le lien entre relationship and ownership (string ou weak).
  • AliGatorAliGator Membre, Modérateur


    Tu dis qu'ils n'existent plus (dernière ligne) alors qu'ils sont retain par le tableau. C'est contradictoire. Du coup, qu'entends-tu par ils "n'existent plus" ? Qu'ils sont invalides ? ça va déboucher sur quelle erreur ?

    Oui je voulais dire par là  qu'ils deviendront invalides. Si ensuite tu essayes de manipuler ces objets et surtout d'accéder à  leurs attributs, tu auras une exception (je ne sais plus exactement laquelle, peut-être bien EXC_BADACCESS, peut-être une plus spécifique, je ne me rappelle plus)
Connectez-vous ou Inscrivez-vous pour répondre.