[Rà‰SOLU] Optimisation des sauvegardes CoreData
Bonjour à tous
Dans mon projet j'ai un tableView dont le dataSource est un NSArray. Pour sauvegarder mes données, j'utilise CoreData. Seulement, je met souvent à jour mes données dans mon app et pour la sauvegarde, j'efface toutes les données puis je les re-sauvegardes. Seulement, quand mon NSArray est beaucoup remplit, la sauvegarde est un peu longue. Je ne pense pas que ce soit une bonne solution...
J'aimerais bien optimiser cette sauvegarde et j'ai quelques idées :
• Sauvegarder seulement ce qui change.
• Effectuer la sauvegarde lorsque l'application est fermée donc utiliser la méthode "applicationWillTerminate".
Pour moi, la deuxième méthode serait la meilleure. Mais je ne sait pas comment aller chercher les données de mon NSArray depuis l'AppDelegate dans ma classe nommée "ViewController".
Avez-vous une idée sur les questions ?
Merci d'avance
Réponses
Donc c'est définitivement ça qu'il fait faire !!! Tu vas grandement y gagner et en plus c'est prévu pour.
2) Utilise plutôt la NSNotification associée à cet événement plutôt que la méthode de ton UIApplicationDelegate, comme ça tu pourras mettre ton code de sauvegarde où ça t'arrange et où cela est le plus logique pour respecter le MVC et l'archi de ton appli.
L'événement applicationWillTerminate a deux défauts :
- un gros défaut : il peut ne pas être déclenché lorsque l'application quitte
- un petit défaut : les opérations lancées sur cet événement doivent durer moins de 5 secondes, donc attention car "... la sauvegarde est un peu longue."
Merci pour vos réponses. Donc je vais m'orienter vers la sauvegarde lorsqu'il y a du changement. Merci aussi à jpimber pour ces infos ça pourra m'être très utile pour mes prochaines apps.
Qu'est-ce que tu entends par dédoubler tes entités ? Je n'ai pas bien compris cette partie là .
Disons que tu as une entité Person et tu décides de créer une classe Person dérivée directement de NSObject.
J'ai jamais trop compris pourquoi certains faisaient ça et dupliquaient leurs structures plutôt que de manipuler directement les NSManagedObject, peut-être que manipuler les NSMO dans le code après les avoir récupéré leur faisaient peur, je sais pas trop... ou peut-être qu'ils croyaient que ça allait modifier directement la base de données CoreData s'ils changeaient les propriétés de leur objet (alors que ça ne le fait que quand tu fais un save sur le MOC relié au PersistantStore)... Bref ça vient certainement d'une incompréhension mais dans tous les cas ça n'a pas d'intérêt et ça complexifie la chose pour rien, surtout au niveau de la récupération et de la sauvegarde de données, ne permettant plus à CoreData de détecter les objets que tu as ajouté/modifié/supprimé automatiquement et perdant plein d'avantages de CoreData.
Alors que si tu manipules directement les NSMO dans ton code (pour remplir tes TableView, passer les objets à ta vue détail), ça te facilite grandement les choses.
En plus, avec les MOC qui peuvent avoir des parentContext maintenant (depuis 10.7 / iOS5), cela facilite aussi les choses si tu as besoin d'avoir un contexte d'édition local, dans lequel tu peux faire des modifications, puis soit les valider (si l'utilisateur clique sur OK) et du coup fusionner ces modifs avec le MOC principal, soit les laisser tomber dans l'oubli (si l'utilisateur clique sur Annuler) en ne les fusionnant pas et laissant ton contexte d'édition se détruire sans appliquer ces modifications sur son MOC parent.
Merci pour à vous deux pour ces explications c'est beaucoup plus claire désormais !
Donc pour reprendre l'exemple, j'ai une entité Person et j'ai créer une classe Person dérivée de NSManagedObjectContext (on clique, dans le modèle CoreData, sur l'entité > Editor > Create NSManagedObject Subclass). Ensuite je récupère les données dans un NSArray avec :
C'est bien cela non ?
Oui et non. Tu peux bien sûr gérer un array via une requête comme tu l'écris. Mais si tu es dans une table view, tu peux surtout utiliser les apis optimisées pour ça : voir cette doc. Le code proposé dans cette doc peut quasiment s'utiliser tel que.
Merci pour cette référence Kubernan ça pourra m'être bien utile puisque dans mon projet j'utilise un tableView.
Et pour faire un update, il suffit simplement de faire :
C'est cela ?
Et un petit refresh table non ?
Oui bien sûr le refresh du tableView mais cela dépend du projet après.
- tu peux être informé en live quand un objet est ajouté/modifié/supprimé de ton jeu de données et ainsi animer juste les rows de ta tableView correspondantes, ce qui permet à la fois d'utiliser des animations d'insertion/suppression sympas et d'éviter de faire un reloadData complet
- le NSFRC ne récupère que les données utiles. Si tu as 1000 lignes dans ton résultat de requête, le NSFRC ne va te récupérer par exemple que les 100 premiers car de toute façon dans ta tableView au départ tu ne vas certainement n'en afficher que 5 ou 10 mais pas 1000 sur un écran. Par contre c'est quand tu vas scroller ta tableView que tu vas afficher les suivants. Quand tu vas arriver aux alentours disons du 80e, le NSFRC va voir que tu te rapproches des 100 et qu'il va lui falloir très probablement la suite si tu continues à scroller, donc il va demander les 100 suivants à CoreData pour que quand tu auras scrollé jusque là il puisse t'afficher la suite. Et ainsi de suite.
En résumé, il gère automatiquement la pagination des données, pour t'éviter d'avoir des requêtes trop lourdes (genre qui mettent trop de temps à s'exécuter car tu as trop de résultat d'un coup, et en plus qui prennent de la place si tu gardes tous les 1000 résultats dans un gros tableau utilisant plus de mémoire que le nombre d'objets dont tu as effectivement besoin pour l'affichage...
- sans parler qu'il gère aussi un cache local de données pour accélérer encore plus les fetches.
Du coup plus besoin d'un NSArray pour garder en mémoire tous les objets que tu veux afficher dans ta tableView. Tu demandes directement au NSFRC l'objet à l'indexPath X et il se charge du reste, de le retourner s'il l'a déjà dans son cache, le récupérer et le mettre en cache sinon, vider le cache quand il n'est plus nécessaire, paginer les résultats pour accélérer le tout...
En bref, je t'invite à te pencher dessus au c'est très efficace et te facilite la vie une fois que tu as compris comment ça marche.
Ha oui c'est une très bonne chose pour optimiser la rapidité de l'app avec CoreData. Il va falloir que je m'y mette rapidement. Merci pour toutes ses explications AliGator c'est bon à savoir.