[CoreData App] gestion du "isEdited" des multiples fenêtres

ClicCoolClicCool Membre
22:31 modifié dans API AppKit #1
Bonjour,

Dans une CoreData App (non document-based) je dois ouvrir une fenêtre à  part pour visualiser/editer certains objets (et tous les sets d'objets liés). Chaque fenêtre a son propre MangedObjectContext.
Le problème c'est qu'à  l'ouverture de la fenêtre j'instancie toute une collection d'objets prêts à  être saisis (bien sur en inhibant le undoManager pendant cette manip).
Du coup, si je binde le "document edited" de ma fenêtre à  MangedObjectContext.hasChange, le document apparait comme dirty dès son ouverture avec le petit point noir dans le rond rouge de fermeture.
De même pour le menu Save qui ne peut se baser sur ce hasChange pour déterminer s'il est enable ou pas.


Pour l'instant je m'en sorts en utilisant UndoManager.canUndo (en partant donc du principe que mes tripatouillages d'objets quand le undoManager est désactivé n'on aucun besoin d'être sauvegardés mais que si un undo est possible c'est que l'utilisateur a édité quelque chose qui peut être sauvegarder).
Le problème c'est qu'à  la différence du hasChange sus-cité, le canUndo d'un UndoManager n'est pas KVObservable (y'a pas de setter).
Je m'en sorts ici en créant une pseudopropriété de mon WindowController qui renvoie la valeur de UndoManager.canUndo et pour laquelle j'ai créé un setter qui ne fait rien mais que j'appèle, pour activer la KVObservation, chaque fois que je reçois la notification NSUndoManagerCheckpointNotification.

ça marche, je peux binder mon documentEdited dessus sans problème, mais est-ce vraiment une solution élégante ?

- la NSUndoManagerCheckpointNotification est très fréquemment envoyée et ça doit générer beaucoup d'activation de mes bindings sur mon canUndo maison...
Y a-t-il une autre notification plus appropriée pour être sûr de pas louper un changement d'état du canUndo?
Peut être que la NSManagedObjectContextObjectsDidChangeNotification du MOContext serait plus économe ? (en vérifant juste le isUndoRegistrationEnabled avant d'appeler mon setter fictif ?)

- Ou peut-être fais-je fausse route en basant ma gestion du dirty sur le undoManager ?
(N'étant surement pas le seul avec ce dilemme, si mon approche était bonne il me semble qu'Apple aurait rendu le canUndo observable, comme il l'a fait récemment avec le hasChange ...non?)

Pour ceux qui ont eu le courage de lire ma prose, vos avis sont les bienvenus.
Merci.

Réponses

  • CéroceCéroce Membre, Modérateur
    22:31 modifié #2
    Chaque fenêtre a son propre MangedObjectContext.


    C'est là  qu'est ton problème. Un ManagedObjectContext correspond à  un seul document. Ce qu'il faut faire, à  mon avis, c'est associer la seconde fenêtre au même NSPersistentDocument.
    Regarde la doc de NSDocument à  ce propos (je n'ai pas retrouvé, mais je suis sûr que la doc d'Apple a un paragraphe quelque part à  ce propos. Voir la méthode -[NSWindowController setDocument:]).
  • ClicCoolClicCool Membre
    22:31 modifié #3
    merci Céroce,

    Dans le principe t'as raison et si je pouvais faire une gestion de type document-based ce serait certainement plus simple.

    Le problème c'est la nature des données ne s'y prète pas.

    Et qu'en plus et par contre, sur le plan interface hmaine, chacun des objet d'une des entité est perçu comme un document.
    L'utilisateur s'attend donc à  pouvoir ouvrir une fenêtre par objet, les consulter, les éditer, utiliser les undo/redo et sauvegarder ces objets et leurs objets liés comme s'il s'ajissait de documents indépendants.
    Alors qu'il est primordial donc, côté data, que tout ce fatra soit lié et puisse, par une autre appli, être ouvert, trié, 'statistiqué' dans un seul ObjectContext.

    J'ajoute que si je devais tout splitter en documents séparés (quite à  "merger" ensuite le tout dans l'appli de gestion globale), ça me ferait tout de même une dizaine de millier de documents à  caser dans un Bundle sous un identifiant unique ... :(

  • CéroceCéroce Membre, Modérateur
    22:31 modifié #4
    J'ai réfléchi à  ton problème, et j'ai peut-être une solution.

    Normalement, un NSPersistentDocument possède un NSManagedObjectsContext et un NSUndoManager. Son Managed Objects Context écrit dans son propre Persistent Store.

    La question est de savoir si on peut faire des écritures sur un Persistent Store déjà  ouvert. D'après ce que j'ai compris, tu es parti sur le principe que oui, puisque chaque fenêtre possède un Managed Object Context qui lit et écrit le même Persistent Store.

    Dans ce cas, je ne vois pas pourquoi chaque fenêtre ne serait pas un document. Tu aurais 2 sous-classes de NSPersistentDocument:
    - la classe de documents "Liste des fichiers"
    - la classe de documents "édition d'un fichier".

    Je t'avoue que je doute quand même beaucoup que plusieurs Managed Objects Contexts puissent accéder au même Persistent Store.
  • ClicCoolClicCool Membre
    22:31 modifié #5
    dans 1256308567:

    J'ai réfléchi à  ton problème, et j'ai peut-être une solution.

    Normalement, un NSPersistentDocument possède un NSManagedObjectsContext et un NSUndoManager. Son Managed Objects Context écrit dans son propre Persistent Store.


    Ah ?
    Autrement dit j'inverserai la problématique.
    Au lieu de chercher à  mimer le comportement d'un document, je partirai d'une structure documentBased que je modifie pour rediriger tout sur le même store ...

    Pas idiot ça,
    Je vais voir un peu ce que ça peut donner ;)
    Merci.


    dans 1256308567:
    Je t'avoue que je doute quand même beaucoup que plusieurs Managed Objects Contexts puissent accéder au même Persistent Store.


    Si si c'est possible, faut "juste" gérer proprement les éventuels conflits.
    Y'a quelques recommandations sur le sujet ici: Core Data Programming Guide: Change Management

  • CéroceCéroce Membre, Modérateur
    22:31 modifié #6
    dans 1256310863:

    Je vais voir un peu ce que ça peut donner ;)


    Je n'ai vraiment aucune certitude, mais je pense que tu vas moins de battre avec Core Data, et puis tu disposeras d'un NSDocument qui va gérer beaucoup de choses à  ta place.

    dans 1256308567:

    Si si c'est possible, faut "juste" gérer proprement les éventuels conflits.


    C'est vrai que c'est une base de données après tout.

  • ClicCoolClicCool Membre
    22:31 modifié #7
    dans 1256317474:

    dans 1256310863:

    Je vais voir un peu ce que ça peut donner ;)


    Je n'ai vraiment aucune certitude, mais je pense que tu vas moins de battre avec Core Data, et puis tu disposeras d'un NSDocument qui va gérer beaucoup de choses à  ta place.


    De toutes façons la piste mérite d'être explorée ;)
Connectez-vous ou Inscrivez-vous pour répondre.