Annuler des modifications dans un nouveau document Core Data
Bonjour,
Lors de l'ouverture d'un nouveau document Core Data, je souhaite mettre en place une "structure par défaut" constituée de deux objets uniques. Mais bien sûr, ceci provoque une modification du document qui va lancer le dialogue d'enregistrement du document à la fermeture, même si, du point de vue de l'utilisateur, il ne s'est rien passé (autrement dit, il doit annuler l'enregistrement d'un fichier auquel il n'a pas touché)...
Pour éviter cela, je dois donc insérer mes objets et "faire oublier" cette modification au document. Je procède comme suit : dans le windowControllerDidLoadNib, après avoir inséré mes objets, je place
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5*NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
[[self managedObjectContext] processPendingChanges];
[[[self managedObjectContext] undoManager] removeAllActions];
[self updateChangeCount:NSChangeCleared];
... je suis obligé de différer ce code parce que Core Data effectue ses insertions après la boucle d'événement courante.
Sous Mountain Lion, je pouvais même utiliser un dispatch time de zéro, tout se passait bien. Mais dès Mavericks, j'ai dû graduellement augmenter ce temps jusqu'à 0.5 seconde. Non seulement ça se voit (le point noir au centre du bouton rouge de la fenêtre a le temps d'apparaà®tre fugacement, ce qui est moche) mais ce temps ne suffit pas pour le premier document ouvert. Après, ça marche.
Questions:
Cette façon de faire est-elle la meilleure ? En existe-t-il une autre, plus élégante ? Ou s'agit-il d'une erreur de conception plus grave ?
D'avance merci.
Réponses
Merci AliGator. En effet, j'avais dû googler ailleurs...
Le problème... c'est que ça ne fonctionne pas. Le document est marqué comme modifié, et je me retrouve face à l'affreux dialogue "Voulez-vous enregistrer?"...
Voici.
Le document n'a pas encore de store à cette phase :
This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.
Et avant que quelqu'un pose la question, mon NSUndoManager n'est pas nil.
Bonjour,
Personnellement j'utilise ce code à la fin du windowControllerDidLoadNib de mon NSPersistentDocument :
Bonjour fleurantin,
J'utilise le même code (removeAllActions semble appeler enableUndoRegistration) mais je suis obligé dans ce cas de précéder mes instructions qui modifient le document d'un disableUndoRegistration, sinon le UndoManager m'envoie une erreur.
Et si ces instructions fonctionnent effectivement, je n'échappe pas au dispatch. Les messages au UndoManager semblent être envoyés dans la boucle en cours, mais Core Data modifie le contexte une fois la boucle terminée (il y a une raison à cela, la possibilité de poster un message à l'utilisateur, je crois).
Même justifiées, ces exécutions différées ont un côté agaçant. En tout cas, on a intérêt à bien lire la doc pour y trouver cette information...
Au fil de mes lectures, je remarque une chose: un ManagedObjectContext possède son propre NSUndoManager. J'en déduis qu'il y en a peut-être un autre qui traà®ne dans le coin (mais je ne sais pas où, dans NSDocument peut-être) et qui continue de stocker les modifications, rendant le document "sale".
J'ai essayé de tout ramener au seul NSUndoManager de Core Data de la façon suivante:
Mais ça continue à fonctionner de façon erratique. Et donc, je ne sais plus que faire d'autre...
Note que NSPersistenceDocument pointe bien sur l'undo manager du MOC.
Juste, je viens de voir ça:
Autrement dit, non seulement mon code est inutile. mais il est dangereux. Si ça se trouve, il va même créer une nouvelle instance de NSUndoManager...
Je pense qu'il faut forcer le chargement des données dès le début du windowControllerDidLoadNib du Document.
CoreData va charger tout ce qui te faut immédiatement au lieu de le différer.
Et tu pourras en suite exécuter l'annulation des opérations à la fin du windowControllerDidLoadNib :
Re-bonjour sur ce sujet, fleurantin!
Si tu regardes mon message #5, tu verras que je fais un fetch pour vérifier si les données sont déjà dans le fichier. Si elles n'y sont pas, je désactive l'enregistrement du undo, j'insère mes objets, je flush les changements et je réactive le undo. Je fais tout comme Apple a marqué.
Et... point noir dans la bulle rouge: document modifié.
Mais ce point disparaà®t si je dispatch_after mes changements: donc c'est bien une affaire de boucle en cours. Donc soit il y a un "bug" (si on peut l'appeler comme ça...) dans Core Data, soit dans la doc, soit chez moi: en ce moment, je jette un coup d'oeil à Grand Central Dispatch pour voir si j'ai loupé un truc...