Explication sur les #import et la déclaration de constante
Greensource
Membre
Bonjour! Il y a un point que je ne n'arrive pas à saisir avec Objective-C.
Si par exemple j'ai trois classes: Kit,A et B.
Dans Kit:
je déclare une constante: const NSUInterger kMaConstante = 0;
Dans A:
J'importe Kit: #import "Kit.h";
Dans B:
J'importe A: #import "A.h";
Et là sur un code de ce genre Xcode me dit que j'ai une définition multiple de kMaConstante?
Du coup la seule raison que j'ai pu voir c'est que l'import réécrivaient tout à chaque fois! Mais je trouve pas ça logique du tout, donc en gros je comprend rien
Si par exemple j'ai trois classes: Kit,A et B.
Dans Kit:
je déclare une constante: const NSUInterger kMaConstante = 0;
Dans A:
J'importe Kit: #import "Kit.h";
Dans B:
J'importe A: #import "A.h";
Et là sur un code de ce genre Xcode me dit que j'ai une définition multiple de kMaConstante?
Du coup la seule raison que j'ai pu voir c'est que l'import réécrivaient tout à chaque fois! Mais je trouve pas ça logique du tout, donc en gros je comprend rien
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Quand j'écris "inclure" cela signifie que le compilateur fait comme si le fichier .h était intégré dans le fichier qui l'inclus.
Le problème d'include, c'est que si un fichier est déjà inclus, tu risques de te retrouver avec des symboles définis plusieurs fois. Habituellement, ceci se règle de la façon suivante:
Comme c'est ennuyeux, ObjC comprend la directive de compilation #import. Elle est équivalente à #include, sauf que le compilateur vérifie si le fichier n'a pas déjà été inclus.
Du coup, ton exemple est mauvais.
Il n'est pas normal de déclarer const NSUInterger kMaConstante = 0; dans un .h.
Un .h sert à fournir une "interface" aux autres fichiers sources.
Ce qui est normal est d'avoir:
Dans Kit.h:
extern const NSUInterger kMaConstante;
Dans Kit.m:
const NSUInterger kMaConstante = 0;
1) C'est du C et pas spécialement de l'Obj-C. Si tu as à programmer en C, tu peux utiliser la même méthode qu'expliquée par Céroce donc pour le même but.
2) Ce mot clé tel qu'utilisé ici déclare que ta constante pourra être accessible depuis d'autres fichiers C de ton projet, et pas que le fichier C qui la déclare et la définit. Si tu veux limiter sa portée au fichier C (ou Obj-C) courant, le mot clé "extern" n'est pas nécessaire.
En fait le mot extern en C n'est pas nécessaire, une déclaration du type const int kMaConst; est considérée comme extern.
En fait le plus simple dans ce cas est d'utiliser enum:
Dans un fichierA déclarant la variable, on ne met pas le qualifier extern, que la variable soit déclarée avec const ou non.
Par contre si dans d'autres fichiers fichierB, fichierC, .. on veut avoir accès à cette variable, on fait une déclaration qui "promet" que la variable existe à l'exécution même si elle n'est pas présente dans ces fichiers.
J'essaye une nouvelle explication.
Pour reprendre l'exemple de Philippe, j'ai trois fichiers, l'un qui déclare une constante, les deux autres qui l'utilisent (je prends l'extension .c mais je pourrais faire pareil avec .m):
ficA.c:
[tt]const int val = 5;[/tt]
ficB.c:
[tt]extern const int val;[/tt]
ficC.c:
[tt]extern const int val;[/tt]
Mais c'est plus propre d'organiser les fichiers de la façon suivante:
ficA.h:
[tt]extern const int val;[/tt]
ficA.c:
[tt]const int val = 5;[/tt]
ficB.c
[tt]#import "ficA.h"[/tt]
ficC.c
[tt]#import "ficA.h"[/tt]
Entièrement d'accord sur la définition dans les .m ou .c et non dans les .h
Pour le reste, je ne dirais pas que c'est plus propre : Faire #import "ficA.h" réalise l'écriture de extern const int val; dans les fichiers ficB.c et ficC.c et en plus recopie la totalité de "ficA.h"
Donc si on veut inclure la totalité du ficA.h il faut procéder comme tu l'indiques, si par contre seule la variable val a un intérêt pour ficB/ficC, on ne voit pas la nécessité d'inclure le fichier tout entier (bien que c'est peut-être chipoter ici, le compilateur ne faisant peut-être aucune copie physique ... )
Cette seconde option, je la rencontre assez souvent quand il s'agit non de variables mais de fonctions utilitaires codées en C.
extern NSImage * thumbnail(NSImage* image, NSSize newSize);
extern void translateRect(NSRectPointer rectPtr,NSSize vector);