Méthodes et @propery protégées en Objective-C

colas_colas_ Membre
octobre 2013 modifié dans Objective-C, Swift, C, C++ #1

J'ai trois classes : ClasseMère et ClasseFille1 et ClasseFille2.


 


Dans ClasseFille1 et ClasseFille2, j'utilise la même méthode technique :



- (void)doSomethingTechnicalWith:(id) anObject

Cette méthode est factorisable : je peux l'implémenter dans ClasseMère. Mais, je ne souhaite pas la rendre publique.


 


Est-ce un cas que vous rencontrez ?


Comment faites-vous dans ce cas-là  ? Vous la rendez quand même publique ? Il y a une autre façon de faire ?


 


Merci !


Réponses

  • samirsamir Membre
    septembre 2013 modifié #2

    Salut,


     


    Y a pas vraiment de méthodes public/protected,... en objective C. y des méthodes public et le reste il faut le faire avec des convention du langage. 


     




     


    Comment faites-vous dans ce cas-là  ? 


     




     


    je déclare une catégorie pour mettre tous les truc privées dedans, ensuite tu peux importer ce fichier dans ClasseFille1 et ClasseFille2. 


  • tabliertablier Membre
    septembre 2013 modifié #3

    Il est possible de faire une catégorie sur deux classes ?  Je ne saisis pas bien là !


     


    Si c'est bien ce que je crois, je fais une catégorie sur NSApplication et effectivement j'importe le .h dans tous les .m qui ont besoin des méthodes factorisées. Parfois, si un grand nombre de classe ont besoin de ces méthodes, j'importe le .h dans le .pch, ce qui évite des tas de #import "la_category.h" disséminés dans les .m


    Il y a peut être plus astucieux.


  • AliGatorAliGator Membre, Modérateur
    Je fais pareil que samir:

    // ClasseMere.h
    @interface ClasseMere : NSObject
    - (void)methodePublique;
    @end

    // ClasseMere+Private.h
    @interface ClasseMere (Private)
    - (void)methodPrivee;
    @end

    // ClasseFille1.h
    #import "ClasseMere.h"
    #import "ClasseMere+Private.h"
    @interface ClasseFille1 : ClasseMere
    ...
    @end
    Comme ça toutes les méthodes privées de ClasseMere sont regroupées dans un header dédié (dans une catégorie sur ClasseMere), et seules les sous-classes font un #import "ClasseMere+Private.h" pour connaà®tre les méthodes privées de ClasseMere qu'ils peuvent appeler.
  • colas_colas_ Membre
    septembre 2013 modifié #5

    OK !


    C'est bien ce que je pensais mais en même temps je me dis : bonjour l'accumulation de fichiers !!!


     


    Est-ce que c'est vrai que cette méthode ne marche pas si les méthodes privées en question utilisent des @properties privées ?


     


     


    @samir : pour public/private, ce que je voulais dire, c'est que le compilateur va m'empêcher de compiler le projet si j'envoie un message à  un objet qui n'est pas dans la liste des méthodes déclarées dans le header.




  •  


    Est-ce que c'est vrai que cette méthode ne marche pas si les méthodes privées en question utilisent des @properties privées ?


     




     


    Tu parles des properties ou des ivars private ?


     


    Tu peux spécifier au iVars leurs visibilité : @protected, @private, @public. par défault elles elles sont protected, donc elle sont accessibles par les sous-classes, mais si tu spécifie @private dans ce cas elles ne sont pas accessibles dans la sous classe ( et ailleurs aussi), accessible juste dans la classe mère.  

  • OK !


  • AliGatorAliGator Membre, Modérateur

    Est-ce que c'est vrai que cette méthode ne marche pas si les méthodes privées en question utilisent des @properties privées ?

    Heu pourquoi ? J'ai pas dû comprendre la question, tu peux préciser ? (Jamais eu de soucis de mon côté)
  • Imagine que j'ai une ClasseMere, avec des @property définies dans ClasseMere().


    Est-ce que j'y aurai accès dans ClasseMere(Private) ?

  • AliGatorAliGator Membre, Modérateur
    Etant donné que ClasseMere(Private) est une catégorie de ClasseMere, et donc que tu vas évidemment être obligé de " #import "ClasseMere.h" " dans "ClasseMere+Private.h", évidemment que tu auras accès à  tout ce qui est déclaré dans ClasseMere.h aussi dans ClasseMere+Private.h ;)
  • Oui mais justement je parlais d'une @property qui n'est pas définie dans ClasseMere.h mais qui est définie dans ClasseMere().


  • AliGatorAliGator Membre, Modérateur
    Bah dans ces cas là  si tu la mets dans ClasseMere() c'est que c'est une @property privée, non ? Donc autant la mettre dans la catégorie ClasseMere(Private) dans "ClasseMere+Private.h", plutôt que dans l'extension de classe ClasseMere() de "ClasseMere.m", justement !
  • @Ali : Oui !


     


    Utilises-tu systématiquement une catégorie ClasseMère(Private), définie dans un .h à  part ?


    Ou bien restes-tu plus souvent avec une simple ClassMère() définie dans le .m de ClasseMère ?


  • Je pense que @colas2 est un peux confus :).


     


    On peux déclarer de deux manière une catégorie, soit dans l'implémentation de la meme classe ( c'est une extension de la classe).


    example :



    @interface MyClass :NSObject 
    @property (strong) NSString  *unepropertyPublic;
    ...
    @end

    maintenant dans l'implémentation de MyClass



    #import "MyClass.h"

    @interface MyClass()
    @property (strong) NSString *unePropertyPrivate;
    @end

    @implementatio MyClass
    .....
    @end

    Avec cette méthode de déclaration de property privées, tu ne pourra pas y accéder dans les autres classes, mêmes les classes qui héritent ce MyClass.


     


    Par contre tu peux faire autrement ( ce que je t'ai expliqué et @Aligator aussi), tu peux créer un autre fichier qui sera une extension de MyClass. Dans Xcode/Add new file/Objetive C class extension. La Xcode vas te créer MyClass_Private ( Private c'est le nom par exemple que j'ai donné lors de l'ajout de .h). C'est dans cet extension que tu rajoute les méthodes/property privées de ta classe MyClass. Donc MyClass vas devenir :



    @interface MyClass :NSObject 
    @property (strong) NSString  *unepropertyPublic;
    ...
    @end

    implémentation



    #import "MyClass.h"

    #import 'MyClass_Private.h" // Permet d'accéder aux méthodes/property privées de ta class MyClass.

    @implementatio MyClass
    .....
    @end

    Maintenant si tu veux que les méthodes/property privées de MyClass soient visibles dans les classes qui héritent de MyClass, il suffit juste d'importer "MyClass_Private.h" et hop. 

  • samirsamir Membre
    septembre 2013 modifié #15


    Utilises-tu systématiquement une catégorie ClasseMère(Private), définie dans un .h à  part ?




     


    La question est pour @Ali ( d'ailleur @Ali ou @Aligator parce que c'est pas le même sens :)) je réponds commum.


     


    C'est différent une catégorie et une extension de classe (enfin pas vraiment mais..). Une catégorie est utilisé pour eténdre des classes existantes, par des méthodes, même si tu n'a pas le code source ( l'implémentation de la classe) comme NSString par exemple.


     


    L'extension de la classe est comme une catégorie, d'ailleurs on dit aussi catégorie anonyme,  est utilisée pour étendre une classe mais il faut qu'elles soient compilées ensemble ( la classe elle même et l'extension de la classe),  elle permet aussi de rajouter des méthodes et des property, et c'est la qu'on déclare les "Private" (méthodes et property) de la classe.


     


    Resumé :


     


    Catégorie pour des étendre des classes dont on a pas le code source (implémentation) NSString, NSArray,...


    Classe extension: C'est pour déclarer les parties "Private" de la classe.


     


     




    Ou bien restes-tu plus souvent avec une simple ClassMère() définie dans le .m de ClasseMère ?




     


    ça dépend, si j'ai besoin des méthodes privées ou property dans les classes filles, je crée un autre .h sinon je reste dans l'implémentation. ( On peux l'utiliser aussi dans les tests unitaires, si on a besoin de tester les méthodes privées dans une classe).


     


    Plus de lecture : https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html


  • AliGatorAliGator Membre, Modérateur
    Pareil que samir.

    En général juste une extension de classe dans le .m
    Quand j'ai besoin que d'autres classes aient accès à  l'API privée, à  la place je fais un fichier .h séparé.

    La différence entre une extension de classe et une catégorie est que l'extension de classe vérifie que les méthodes que tu as déclarées dans l'extension est bien présente dans son implémentation, et si c'est pas le cas il gueule lors de la compilation.
  • colas_colas_ Membre
    septembre 2013 modifié #17


    Quand j'ai besoin que d'autres classes aient accès à  l'API privée, à  la place je fais un fichier .h séparé.

     




     


    Mais tu ne fais pas de .m séparé ?


     


    C'est-à -dire que tu as :


     


    MyClass.h


    MyClass+Private.h


    MyClass.m


     


     


    ça me semble plus pratique que de bouger l'implémentation des méthodes/properties semi-privées.


    Car, pour implémenter ces méthodes, on a besoin d'autres méthode privées... et en tirant sur le fil de la bobine, on se retrouve à  tout déplacer vers la catégorie !!!


     


     


    Donc pas de MyClass+Private.m ?


     


  • AliGatorAliGator Membre, Modérateur

    Donc pas de MyClass+Private.m ?

    Non, pas besoin.


    // MyClass.h
    @interface MyClass : NSObject
    -(void)publicMethod;
    @end
    // MyClass+Private.h
    #import "MyClass.h"

    @interface MyClass ()
    -(void)privateMethod;
    @end
    // MyClass.m
    #import "MyClass+Private.h" // et MyClass+Private.h inclus déjà  MyClass.h

    @implementation MyClass
    -(void)publicMethod { ... }
    -(void)privateMethod { ... }
    @end
    Après tu peux mixer selon tes besoins évidemment. Si tu as besoin d'un côté d'une API vraiment privée uniquement visible par le .m et d'une autre API qui elle serait semi-privée, accessible quand même à  tes sous-classes, tu peux mettre ton extension de classe dans le .m (API vraiment privée), et une catégorie (ton API semi-privée) dans MyClass+Private.h (que tu pourras ainsi #importer dans les sous-classes). Tu fais selon tes besoins, mais l'important est de rester cohérent et de ne pas exposer à  tous une API qui n'a pas besoin d'être connue et utilisée par l'extérieur.
  • OK Cool.


     


    Merci, je vais essayer maintenant de coder selon ces conventions ;-)


  • Je viens de m'apercevoir que



    It is not possible to add members and properties to an existing class via a category " only methods.

    Comme je déclare aussi des @property dans MyClass(), je pensais que c'était possible dans MyClass(Private).


    J'arrive à  les déclarer, mais quand mon programme tombe sur 



    setProperty:

    où property est définie dans MyClass(Private), il bugue.


     


    D'où ma question : comment faites-vous pour les @property ?


    Plus précisément, j'ai une @property d'une classe mère que je veux rendre visible pour les classes filles. Comment faire ?


  • colas_colas_ Membre
    octobre 2013 modifié #21

    Je réponds moi-même à  ma question : 



    // MyClass.h

    @interface MyClass : NSObject

    -(void)publicMethod;
    @property id publicProperty;

    @end


    // MyClass+Private.h

    #import "MyClass.h"

    @interface MyClass (Private)

    -(void)protectedMethod;
    @property id protectedProperty;

    @end



    // MyClass.m

    #import "MyClass+Private.h" // et MyClass+Private.h inclus déjà  MyClass.h

    @implementation MyClass()

    @property id protectedProperty;

    -(void)privateMethod ;
    @property id privateProperty;

    @end

    @implementation

    MyClass -(void)publicMethod { ... }
    -(void)privateMethod { ... }

    @end

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