Utilisez-vous @class ?

NeofelisNeofelis Membre
mai 2011 modifié dans API AppKit #1
Bonjour,

J'ai un livre qui conseille de placer les @class maClass dans les fichiers .h (l'en-tête) et l'inclusion de la classe (import "maClasse.h") dans les fichiers .m (l'implémentation). Y'a-t-il une utilité à  cette méthode (mise à  part pour résoudre les dépendances circulaires) sachant qu'en plaçant les import directement dans le fichier.h cela marche tout aussi bien (vu que le .h est lui dans tous les cas inclus dans le .m) ?

Réponses

  • AliGatorAliGator Membre, Modérateur
    10:42 modifié #2
    Oui il y a un intérêt en particulier d'utiliser ces @class, c'est au niveau de la compilation.

    Si tu "#import maClass.h" dans ton fichier "moncode.h", dès que tu vas modifier l'interface de ta clase maClass par exemple en rajoutant une méthode, le maClass.h va être modifié, et comme il est #importé dans moncode.h, moncode.h va être recompilé, et tous les fichiers qui #import moncode.h également, etc... du coup ça recompile beaucoup de choses en général pour rien.

    Alors que si tu ne "#import maClass.h" que dans ton fichier d'implémentation "moncode.m", seul moncode.m sera recompilé, et les fichiers qui incluent moncode.h ne seront pas affectés et pas recompilés, ce qui est plus logique car il n'y a aucune raison de tout recompiler pour ça.

    Donc utiliser les @class dans ton .h et les #import dans ton .m te permet d'éviter que Xcode recompile plein de fichiers inutilement si tu as modifies ton "maClass.h", mais qu'il ne recompile que le nécessaire.
  • APAP Membre
    10:42 modifié #3
    Merci, je n'ai pas posé la question mais j'aurais appris qqlch aujourd'hui :)
  • NeofelisNeofelis Membre
    10:42 modifié #4
    Merci AliGator o:)
  • mai 2011 modifié #5
    dans 1305506289:

    Oui il y a un intérêt en particulier d'utiliser ces @class, c'est au niveau de la compilation.

    Si tu "#import maClass.h" dans ton fichier "moncode.h", dès que tu vas modifier l'interface de ta clase maClass par exemple en rajoutant une méthode, le maClass.h va être modifié, et comme il est #importé dans moncode.h, moncode.h va être recompilé, et tous les fichiers qui #import moncode.h également, etc... du coup ça recompile beaucoup de choses en général pour rien.

    Alors que si tu ne "#import maClass.h" que dans ton fichier d'implémentation "moncode.m", seul moncode.m sera recompilé, et les fichiers qui incluent moncode.h ne seront pas affectés et pas recompilés, ce qui est plus logique car il n'y a aucune raison de tout recompiler pour ça.

    Donc utiliser les @class dans ton .h et les #import dans ton .m te permet d'éviter que Xcode recompile plein de fichiers inutilement si tu as modifies ton "maClass.h", mais qu'il ne recompile que le nécessaire.


    Pourtant un @class ne suffit pas toujours dans le .h, par exemple lorsque je veux que Toto se conforme au protocol TataDelegate, un @class Tata; dans Toto.h ne suffira pas.. une raison particulière?
  • CéroceCéroce Membre, Modérateur
    mai 2011 modifié #6
    @class Tata; dit au compilateur que Tata est une classe. Ainsi, par exemple, si un Tata* apparait, le compilateur ne générera pas une erreur de symbole inconnu.
    Toutefois, le fichier Tata.h n'est pas importé. Le compilateur ne connaitra pas les méthodes et propriétés de la classe. Si ton protocole TataDelegate y est déclaré, le compilateur ne peut pas connaitre le symbole TataDelegate à  moins d'importer le .h. 

    (Ceci dit, d'aprés mes souvenirs, on peut utiliser la commande @protocol TataDelegate; pour signifier au compilateur que TataDelegate est un protocole. Sans certitude aucune).
  • 10:42 modifié #7
    ça me paraà®t un peu lourd. Dans ce genre de cas je préfère faire un #import "Tata.h" dans Toto.h plutôt que de renseigner @class Tata; et @protocol TataDelegate;
  • CéroceCéroce Membre, Modérateur
    10:42 modifié #8
    Oui, bien sûr, il vaut mieux importer le .h. L'exemple typique de l'utilisation de @class est celui-ci:

    Tata.h

    #import &lt;Foundation/Foundation.h&gt;<br /><br />@class Tata;<br /><br />@protocol TataDelegate<br />@required<br />- (void) tata:(Tata *)aTata didSomethingWithResult:(int)result;<br />@end<br /><br /><br />@interface Tata : NSObject {<br />&nbsp; &nbsp; <br />}<br /><br />@property (nonatomic, retain) id &lt;TataDelegate&gt; delegate;<br /><br />@end
    


    Si on n'écrit pas [tt]@class Tata[/tt]; le compilateur se plaint de la déclaration de la méthode de protocole [tt]tata:didSomethingWithResult:[/tt], puisqu'il ne connait pas le type [tt]Tata *[/tt].
  • 10:42 modifié #9
    Yep. Sinon on peut aussi déclarer @protocol TataDelegate;, et l'implémenter après le @end de Tata.
    <br />@protocol TataDelegate;<br />@interface Tata : NSObject<br />{<br /><br />}<br /><br />@end<br /><br />@protocol TataDelegate &lt;NSObject&gt;<br />....<br />@end<br />
    
  • AliGatorAliGator Membre, Modérateur
    10:42 modifié #10
    En théorie c'est bien mieux d'utiliser juste @class dans notre .h (et/ou @protocol) pour juste dire au compilateur que la classe (et/ou le protocole) existe car il n'a pas besoin d'en savoir plus. Et de ne faire que le #import dans le .m, qui est le seul qui a besoin de savoir quelles méthodes la classe ou le protocole déclarent devoir implémenter.

    En pratique, on est nombreux à  mettre directement un #import dans le .h parce que c'est tellement plus simple.
    Mais c'est pas pour autant qu'on a raison, car en terme d'optimisation du process de compilation ça peut vite augmenter le temps nécessaire à  faire une compilation itérative d'un projet juste à  cause d'une petite modification.
  • FKDEVFKDEV Membre
    10:42 modifié #11
    C'est le genre de détails qui a son importance quand la duréed e la compilation se compte en minutes. Et/ou quand on travaille en équipe et que les autres arrêtent pas de modifier les .h.
  • 10:42 modifié #12
    dans 1306092493:

    C'est le genre de détails qui a son importance quand la duréed e la compilation se compte en minutes. Et/ou quand on travaille en équipe et que les autres arrêtent pas de modifier les .h.

    Surtout si tu bosses sur une machine merdique.
  • FloFlo Membre
    10:42 modifié #13
    Je remonte ce poste car j'ai une petite question concernant l'utilisation de @class, j'ai le code suivant :
    <br /><br />@class ITCollapsibleViewController;<br /><br />@interface ITAddPlaceViewController : ITCollapsibleViewController {}<br /><br />// ...<br /><br />@end<br /><br />
    

    <br />#import &quot;ITAddPlaceViewController.h&quot;<br />#import &quot;ITCollapsibleViewController.h&quot;<br /><br />@implementation ITAddPlaceViewController<br /><br />// ...<br /><br />@end<br />
    


    Pourtant XCode me retourne l'erreur suivante : ITAddPlaceViewController.h:14: error: cannot find interface declaration for 'ITCollapsibleViewController', superclass of 'ITAddPlaceViewController'

    Y aurait-il une exception à  l'utilisation de @Class en cas d'héritage ?  ???

  • FloFlo Membre
    10:42 modifié #14
    Ok, j'ai ma réponse  :D


    The exception to this is that you should #import a class or formal protocol you're inheriting from in your header file (in which case you wouldn't need to import it in the implementation).
  • CeetixCeetix Membre
    10:42 modifié #15
    Oui car l'héritage signifie avoir accès à  toutes les variables membres de ta classe mère.
    @classe ne donne pas accès à  ces variables membres.
    Il faut donc passer par un import.
  • tabliertablier Membre
    10:42 modifié #16
    Chaque fois que je le peux, je met le  #import "xxxx.h" dans le fichier maclasse.m plus tôt que dans le  maclasse.h (sauf si je définis une catégorie). Y-a-t-il des inconvénients à  procéder ainsi ??
  • zoczoc Membre
    10:42 modifié #17
    Non, c'est même recommandé. Ca évite les références circulaires entre .h qui finissent immanquablement pas arriver dès que le projet devient conséquent.


    Dans un .h, il ne faut inclure/importer que le strict minimum nécessaire (donc à  priori on utilise @class foo; et @protocol bar; au maximum, on n'importe pas les déclarations de foo et de bar).

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