Core Data : Managed Object Context et héritage

narknark Membre
22:38 modifié dans API AppKit #1
Hello all, encore moi...

Je reviens à  la charge sur Core Data.
J'ai un modèle d'arbre avec une classe abstraite qui fait office de classe-mère et plusieurs sous-classes, le tout me permettant la gestion d'élément de types différents dans ma structure:

TreeNode : NSManagedObject
    |
   
ClassNode : TreeNode
    |
   
RelationNode : TreeNode
    |
   
AttributeNode : TreeNode
    |
    :
    .


Un NSTreeController gère le tout, et je suis plutôt satisfait du résultat.
Maintenant, je cherche à  récupérer dans un NSArrayController une collection d'objet gérée par NSTreeController.

J'ai connecté mon NSArrayController comme suit:

- Entity Name : TreeNode
- Model Key Path : managedObjectContext

Et j'obtiens bel et bien une collection de TreeNode. Super!
Alors je me suis dit que si je mettais RelationNode comme entité, je ne récupèrerais que les objets de type correspondant. Mais non.

Je voudrais donc pouvoir filtrer le type d'objet managé par mon Array Controller pour obtenir une liste d'instances de RelationNode par exemple.
Est-ce possible?

PS: J'utilise NSPersistentDocument

Réponses

  • Philippe49Philippe49 Membre
    22:38 modifié #2
    Voir du côté de NSFetchRequest
  • narknark Membre
    22:38 modifié #3
    Merci encore Philippe.
    Je vais regarder, implémenter, tester, et je reviendrai surement.  :P
  • yoannyoann Membre
    22:38 modifié #4
    Ce problème m'étonne un peut.

    J'utilise moi même ce système d'ancêtre commun pour gérer par exemple des UUID centralisé. Et pour autant je peut tout à  fait mettre un de ses enfants dans l'entity recherché par NSArrayController.

    Est-ce que tu peut nous faire un proto de ton problème histoire de voir ?
  • ClicCoolClicCool Membre
    22:38 modifié #5
    dans 1255164167:

    Ce problème m'étonne un peu.../...


    Moi aussi,
    ça devrait marcher ainsi ...

    ... même si, à  mon sens, il peut aussi être intéressant de laisser l'entité mère comme "entité officielle" du ArrayControleur et, ponctuellement à  la demande, juste utiliser un FilterPredicate au grès des classes filles que l'on veut.


    <br />// soit TreeNodesACTRL un ArrayControleur gérant des entités &quot;TreeNode&quot;<br /><br />	NSPredicate *predicateur = [NSPredicate predicateWithFormat:&quot;className == &#092;&quot;RelationNode&#092;&quot;&quot;];<br /><br />	[TreeNodesACTRL setFilterPredicate: predicateur ];<br />	[TreeNodesACTRL rearrangeObjects];<br /><br />// TreeNodesACTRL ne contient maintenant plus que les RelationNodes<br />
    


  • AliGatorAliGator Membre, Modérateur
    22:38 modifié #6
    ??? Un revenant ??? !!
    Heureux de te voir de passage parmi nous Hervé :p :p
  • ClicCoolClicCool Membre
    22:38 modifié #7
    Merci Grand Maà®tre Ali,

    Pourfendeur des grincheux, de l'inexactitude et des posts trop courts !


    Tiens, il doit me rester une Cantillon, on va se l'ouvrir !
    :p A la tienne  :p
  • muqaddarmuqaddar Administrateur
    22:38 modifié #8
    Hervé ! Bienvenue revenant !
    J'espère que tu nous reviens pas que pour quelques jours hein ! Allé !

    Très content de te revoir en tout cas. A la tienne !  :p

    ps : désolé de pourrir le post, mais là  c'est pour la bonne cause ! ;)
  • ClicCoolClicCool Membre
    22:38 modifié #9
    Merci Alex  :)

    Tu sais, je sais jamais quand la "vraie vie" m'imposera un balck out !  :-\\

    J'ai perdu un certain nombre d'amis comme ça déjà   :'(

    Mais bon, j'suis là   :brule:

    Mais t'as raison, pourrissons pas le sujet de Nark  ;)
  • GreensourceGreensource Membre
    22:38 modifié #10
    Je crois que mon problème ressemble un peu à  celui de nark.
    J'ai inscrit dans mon modèle Core Data deux entity, une (VLContact) hérite de NSManagedObject et contient juste un attribut name et eMail, deux NSString.
    Et j'ai une autre Entity, VLUser, qui elle hérite de VLContact, c'est bien inscrit dans le model. VLUser ajoute juste l'attribut password, toujours un NSString.

    Donc vu la hiérarchie je peut écrire:
    VLUser* userToSet = (VLUser*)[NSEntityDescription insertNewObjectForEntityForName:@&quot;VLUser&quot; <br />																&nbsp;  inManagedObjectContext:managedObjectContext];<br />		[userToSet setPassword:aPassword];<br />		[userToSet setName:aName];<br />		[userToSet setEMail:anEmail];
    

    Pas de souci, Xcode est d'accord. Mais quand je lance le bousin, j'ai une belle exception comme quoi l'instance de VLContact ne répond pas à  setName:
    -[VLContact setName:]: unrecognized selector sent to instance 0x3c0f2f0


    J'ai surement oublié quelques choses mais je ne vois pas quoi? Je vous joint mon model.
  • yoannyoann Membre
    22:38 modifié #11
    Et avec un setValue:forKey: ça dit quoi ? :-)
  • GreensourceGreensource Membre
    22:38 modifié #12
    Je sent que tu me charrie là ? :)
    Bon ça me marque que VLContact n'est pas KVC compliant mais pourtant je pensais que le .xcmodeldata le faisait directement?

    Je vois pas bien ce que je dois ajouter, des méthodes setValue:forKey: pour chaques attributes?
  • yoannyoann Membre
    22:38 modifié #13
    T'es certain que ta classe mère VLContact est bien hérité de NSManagedObject ? C'est de la que viens la partie KVC
  • GreensourceGreensource Membre
    22:38 modifié #14
    Ouais certain! D'après ça en tout cas:
    #import &lt;CoreData/CoreData.h&gt;<br />@interface VLContact :&nbsp; NSManagedObject&nbsp; <br />{<br />}<br />@property (nonatomic, retain) NSString * firstName;<br />@property (nonatomic, retain) NSString * lastName;<br />@property (nonatomic, retain) NSString * eMail;<br />@end<br />
    

    C'est embêtant en plus tout les tuto ou info que je trouve ne traite jamais de l'héritage...
  • yoannyoann Membre
    22:38 modifié #15
    Ce qui est vachment plus embêtant c'est qu'on a pas a en parler normalement, il n'y a rien de particulier à  faire pour que ça marche ^^

    fait un clean all + build & analyse voir si t'as pas des messages d'erreur intéressant. Je vois pas trop là  comme ça
  • ClicCoolClicCool Membre
    22:38 modifié #16
    -[VLContact setName:]: unrecognized selector sent to instance 0x3c0f2f0


    C'est normal que VLContact réponde pas à  setName.
    Il n'a pas de property name.

    dans 1258641418:

    Ouais certain! D'après ça en tout cas:
    #import &lt;CoreData/CoreData.h&gt;<br />@interface VLContact :&nbsp; NSManagedObject&nbsp; <br />{<br />}<br />@property (nonatomic, retain) NSString * firstName;<br />@property (nonatomic, retain) NSString * lastName;<br />@property (nonatomic, retain) NSString * eMail;<br />@end<br />
    

    C'est embêtant en plus tout les tuto ou info que je trouve ne traite jamais de l'héritage...


    Par contre setLastName ou setFirstName devraient fonctionner sans problème ;)
  • yoannyoann Membre
    22:38 modifié #17
    dans 1258665913:

    Par contre setLastName ou setFirstName devraient fonctionner sans problème ;)


    Tout comme le setValue:forKey: non ?
  • ClicCoolClicCool Membre
    22:38 modifié #18
    ;D

    Ceci dit le [tt]setValue: forKer:[/tt] reste intéressant pour une entité pour laquelle on a pas déclaré une autre classe que NSManagedObject.
    ça évite en effet d'entendre la complainte du compilo au fond des bois.
    Au runTime les accesseurs auront été générés par CoreData et ça marchera.
    Mais du coup il n'y aura aucun contrôle du compilo.
    Et la recommandation de la doc est plutôt de définir une catégorie de NSManagedObject dans laquelle on déclare les Properties du managedObject.
    If you are not using a custom class, to suppress compiler warnings you can declare the properties in a category of NSManagedObject:



    Mais, dès lors qu'on défini et implémente une classe pour une entitée, il faut bien sur déclarer les Properties (ou déclarer et implémenter les accesseurs).
    For example, given an entity with an attribute firstName, Core Data automatically generates firstName, setFirstName:, primitiveFirstName, and setPrimitiveFirstName:. Core Data does this even for entities represented by NSManagedObject. To suppress compiler warnings when you invoke these methods, you should use the Objective-C 2.0 declared properties feature, as described in “Declaration.”
  • GreensourceGreensource Membre
    22:38 modifié #19
    Nail y a eu juste un changement, j'ai renommer un attribut. Mais j'ai toujours le même souci. Pour rappel un VLUser est un VLContact avec un attribut password en plus.
    Donc j'écris:
    VLUser* userToSet = (VLUser*)[NSEntityDescription insertNewObjectForEntityForName:@&quot;VLUser&quot; <br />																&nbsp;  inManagedObjectContext:managedObjectContext];<br />		<br />		[userToSet setValue:anEmail forKey:@&quot;eMail&quot;];<br />		[userToSet setValue:aFirstName forKey:@&quot;firstName&quot;];<br />		[userToSet setValue:aLastName forKey:@&quot;lastName&quot;];<br />		[userToSet setValue:aPassword forKey:@&quot;password&quot;];
    

    et on me répond:
    [<VLContact 0x3c0f190> setValue:forUndefinedKey:]: the entity VLUser is not key value coding-compliant for the key "eMail".'


    J'ai fait un clean complet et rien n'y fait! Tu dit que ça devrais marcher yoann, tu as déjà  été dans le même cas?
  • ClicCoolClicCool Membre
    novembre 2009 modifié #20
    A mon avis t'as du oublier un truc tout simple.

    dans 1258711172:
    .../... Pour rappel un VLUser est un VLContact avec un attribut password en plus.../...

    Par exemple:
    Il ne suffit pas que dans ton modèle VLUser déclare VLContact comme classe parente.
    Il faut aussi, bien sûr, que dans le header de VLUser tu le déclares comme sous classe de VLContact.
    #import &lt;CoreData/CoreData.h&gt;<br />@class VLContact;<br />@interface VLUser :  VLContact  <br />{<br />}<br />@property (nonatomic, retain) NSString * password;<br />.../...<br />@end
    
  • GreensourceGreensource Membre
    22:38 modifié #21
    Oui j'ai vérifié ça et je l'ai bien fait:
    #import &quot;VLContact.h&quot;<br /><br /><br />@interface VLUser : VLContact {<br />	NSString* password;<br />}<br /><br />@property (nonatomic, retain) NSString * password;<br /><br />@end
    

    J'ai juste pas importe Core Data à  cet endroit, mais il l'est dans VLContact.h, ça suffit bien?
  • ClicCoolClicCool Membre
    novembre 2009 modifié #22
    Ah ben, je me disais bien que t'avais juste oublié un truc simple  ;)

    Non ça suffit pas pour un header, faut aussi y importer explicitement coredata.
    [EDIT] en fait pas si sûr mais pas le temps de vérifier, de toutes façons ça vaut le coup d'essayer, d'autant que je trouve l'usage de [tt]@class[/tt] plus propre que de compter sur des imports imbriqués qu'on fini par plus maitriser ...

    Et par contre si c'est pas indispensable (bien rare), mieux vaux simplement déclarer, avec [tt]@class [/tt], une classe qui est référencée dans le header d'une autre que d'importer son header ...
  • GreensourceGreensource Membre
    22:38 modifié #23
    En effet c'est pas le temps que ça prend...mais ça ne marche toujours pas :(

    ps: Par contre quand je met
    @class VLContact;
    

    au lieu de
    #import &quot;VLContact.h&quot;
    


    Il est pas content, surement pcq pour l'heritage il a besoin de tout le header?
  • ClicCoolClicCool Membre
    22:38 modifié #24
    dans 1258713484:
    .../...
    Il est pas content, surement pcq pour l'heritage il a besoin de tout le header?


    Oui t'as raison  :)
  • ClicCoolClicCool Membre
    22:38 modifié #25
    dans 1258712094:

    #import &quot;VLContact.h&quot;<br /><br /><br />@interface VLUser : VLContact {<br />	NSString* password;<br />}<br /><br />@property (nonatomic, retain) NSString * password;<br /><br />@end
    



    Euh, pourquoi déclares-tu la variable password si elle figure bien dans le modèle ? @property suffit non ?
  • ClicCoolClicCool Membre
    22:38 modifié #26
    Dans le genre truc simple, à  part oublier de déclarer la superclasse dans l'interface, y'a l'oubli inverse aussi ...

    T'as bien, dans le modèle, sélectionné la bonne classe parente dans le popUpMenu "Parent" de l'entité fille ?  ::)
  • GreensourceGreensource Membre
    22:38 modifié #27
    :P énéfé je n'avais pas fait le lien, je croyais qu'écrire qui était la classe mère suffisait.
    Et bien merci pour tout, et pardons du dérangement, je range tout en partant...
Connectez-vous ou Inscrivez-vous pour répondre.