Méthodes dynamiques en fonctions des properties

Bonjour à  tous je travaille activement en ce moment et j'aimerai bien palier à  quelques manques de NSObject notamment au niveau du KVO et des NSUndoManager.


Je me heurte à  un soucis que je peux régler avec beaucoup de code ou une astuce. Je préfère l'astuce parce que ça me paraà®t beaucoup plus intéressant.

Quand on code une classe sur Xcode on se retrouve avec des méthodes du type :

+ (NSSet *)keyPathsForValuesAffecting
C'est très pratique et l'existence de ces méthodes est fonction des properties de la classe.


J'aimerai savoir comment faire une telle chose. Le soucis c'est que je ne sais pas quoi chercher je me doute que ça a un rapport avec le Runtime mais la doc est touffue et je ne sais pas exactement ce que je cherche.


Donc si quelqu'un a une piste sur le sujet ça m'aiderai beaucoup. Après je mènerai des tests et je partagerai mon travail si le résultat est concluant :) (j'aurai une bonne raison de découvrir cocoapods)
Mots clés:

Réponses

  • CéroceCéroce Membre, Modérateur

    On peut faire de l'introspection avec le Runtime. En particulier lister les variables d'instance, les propriétés et les méthodes, et savoir de quelle classe une classe hérite.


     


    Cependant, j'aimerais plutôt savoir quels sont les manques que tu as pu observer pour en discuter; il y a peut-être déjà  une solution intégrée.


  • PyrohPyroh Membre

    Je me suis heurté a un soucis relativement con qui m'a demandé d'adapter un peu.


    Quand on utilise beaucoup le KVO et les bindings comme moi y'a certains trucs qu'on trouve un peu bizarre et rigides.


     


    Par exemple j'ai une classe qui gère un couleur et qui en fait un peu plus que NSColor donc qui ne peut pas être une subclass de cette dernière (je rentre pas dans les détails c'est un projet en cours). Je dois pouvoir modifier les paramètres HSB et RGB. Les uns affectant les autres mais surtout la couleur. Si on fait un set sur la couleur c'est RGB et HSB qui sont changés mais qui eux même affectent la couleur... Si j'utilise keyPathsForValuesAffecting<key> alors je vais me retrouver avec une boucle infinie mais les observers seront notifiés.


    La solution est de tout gérer manuellement. J'ai 2/3 méthodes dans une subclass de NSObject pour faire ça.


     


    Le gros problème que j'ai c'est le undo management. C'est bien beau CoreData mais CoreData me rebute clairement. Pour gagner un undoManager je vais me taper 2 semaines à  m'auto-former pour essayer de comprendre comment mettre en place ce que je pourrai faire facilement de manière traditionnelle. Alors j'essaie d'automatiser ça en surchargeant - (void)setValue:(id)value forKeyPath:(NSString *)keyPath pour qu'il enregistre les changements dans le undoManager (idée piquée à  yoann dans un vieux topic) mais il me faudrait des moyens de contrôler tout ça plus finement. Comme par exemple un + (NSDisctionnary)undoManagerOptionFor<key> et je pense que c'est faisable. 


     


    (Je sais pas si ma prose est très claire et m'en excuse je suis sous médication un peu forte pour mon dos  :* )


  • PyrohPyroh Membre
    mai 2014 modifié #4

    Voilà  j'ai un peu creusé l'idée :

    J'ai une méthode de classe :



    + (NSSet *)keyPathsForValuesAutomaticalyAffectingUndoManager;

    Elle me permet de préciser quelles keys vont ajouter une entrée dans le undoManager.

    J'ai également : 



    + (NSUndoManager *)undoManager
    {
    // Méthode la plus propre que j'ai trouvée pour récupérer le undoManage du document
    return [[NSApp delegate] undoManager];
    }

    - (void)setValue:(id)value forKeyPath:(NSString *)keyPath
    {
        if ([[self.class keyPathsForValuesAutomaticalyAffectingUndoManager] containsObject:keyPath]) {
            id obj = [self valueForKeyPath:keyPath];
            [[[self.class undoManager] prepareWithInvocationTarget:self] setValue:obj forKeyPath:keyPath];
        }
        [super setValue:value forKeyPath:keyPath];
    }

    Pour le moment les vrais keyPaths ne passeraient pas vu que je ne gère pas la syntaxe avec les points (ça viendra après ça). Pour ce qui est du selector sur le setter je ne pense pas qu'il y ait un soucis vu que c'est toujours set<Prop_name>: ^^

     

    Maintenant le problème qui reste c'est qu'il n'y a que le UNDO qui fonctionne le REDO ne veut rien savoir :(


  • CéroceCéroce Membre, Modérateur
    mai 2014 modifié #5
    Malheureusement, ce n'est pas aussi simple que ça. Effectivement, ça fonctionne pour une valeur seule, mais l'undo peut affecter plusieurs valeurs en même temps. Et puis, tu ne peux pas grouper les opérations, ni leur donner un titre. Mais admettons.

    Par contre, ça a quand même une grosse limitation: il faut absolument appeler -setValue:forKeyPath: pour modifier la propriété. De fait, l'undo fonctionne effectivement quand on la modifie par un binding, mais pas quand on passe par l'accesseur.

    Pour moi, certes, ça fait gagner du temps en codage, mais c'est une demi-solution.
  • PyrohPyroh Membre

    Oui effectivement ça fonctionne mais ça limite pas mal... (j'ai corrigé le code d'au-dessus qui avait un sale bug, au passage)


     


    Quelle serait la bonne pratique alors ? Implémentation directe dans les setters ? Dans le contrôleur ?


    Je trouve assez peu d'exemple correct évitant le boilerplate sur le net  :(


  • CéroceCéroce Membre, Modérateur

    Mon expérience est qu'il faut coder l'undo au niveau des setters. Ce qui implique qu'il faut passer l'undo manager à  tous les objets... je n'ai pas de meilleure solution à  te proposer.


  • MalaMala Membre, Modérateur

    A contrario de Céroce, j'ai pour habitude de considérer NSUndoManager comme un objet exclusivement lié à  mes contrôleurs. Les objets models et views n'en voient donc pas la couleur mais sont capables de s'auto décrire et modifier à  loisir sur demande du contrôleur qui les manipulent.


  • PyrohPyroh Membre
    J'étais aussi parti pour une approche basée sur les setters en mettant le document en nsappselegate pour récupérer le undoManager depuis NSApp.

    Mais je dois dire que le :


    Les objets models et views n'en voient donc pas la couleur mais sont capables de s'auto décrire et modifier à  loisir sur demande du contrôleur qui les manipulent.

    de Mala m'intéresse au plus au point :)


    Tu pourrais m'en dire plus ? Si tu ne veux pas me donner de code je comprendrai aisément ;)
  • MalaMala Membre, Modérateur

    Je pense que je ne te serais malheureusement guère utile car je code quasi exclusivement à  l'ancienne. Je conserve donc une parfaite maà®trise de mes objets (view ou model) dont toute modification passe par le(s) contrôleur(s).


     


    Néanmoins, dans le cas particulier de KVO qui t'intéresse, as-tu pensé aux notifications? Au lieu d'enregistrer lui même les données, l'objet enverrait juste une notification (NSNotification) avant sa modification. Le contrôleur, qui chapeaute tes objets, est à  l'écoute et il peut alors faire son travail en interrogeant l'objet qui l'a notifié pour sauvegarder son état. C'est un peu plus lourd mais cela me semblerait plus respectueux du paradigme MVC. A méditer...


  • Le undo reste une superbe fonctionnalité de CoreData.


Connectez-vous ou Inscrivez-vous pour répondre.