Constantes
ChiCo
Membre
Bonjour a toutes et tous !
Je débute sur xcode et voudrais développer une appli pour mon iPhone 4, pour me simplifier la vie (je travaille dans la clim).
Elle est relativement basique qui va effectuer un calcul puis j'aimerai créer un pdf récapitulatif et l envoyé a mon boss.
J'ai donc créer un nouveau projet en Objective-C (via plusieurs tutos sur le net), avec les icones, launchimage ...
Je voudrais juste savoir comment créer des constantes ?
J'ai créer un fichier "Constantes.h" avec a l'intérieur
#define "GP72" = 0
#define "GP90" = 0
#define "GP108" = 1.2
#define "GP126" = 3.3
#define "GP144" = 3.3
Ma façon est elle bonne ?
Et dans mon "ViewController.m"
#import "Constantes.h" // Load des constantes
Merci par avance !
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Alors non, ce n'est pas une bonne façon.
1) Mauvaise syntaxe
Un "#define" ne fait que déclarer un terme à rechercher/remplacer automatiquement par le compilateur lors de la compilation. Ici ça ne va pas remplacer toutes les occurrences de GP108 par 1.2, mais remplacer toutes les occurrences de "GP108" (note les guillemets, inclus). D'ailleurs je ne sais même pas si c'est une syntaxe valide, je ne pense pas (ton code ne doit sans doute pas compiler)
Si tu voulais vraiment utiliser un #define, il faudrait plutôt écrire :
Pour dire au compilateur "avant de compiler quoi que ce soit, fait un rechercher/remplacer dans mon code pour remplacer toute occurrence du token GP108 par 1.2, verbatim (au caractère près)".
2) Mauvaise idée
Mais de toute façon, utiliser "#define" est une mauvaise pratique pour déclarer des constantes. Certains l'utilisent (je ne sais pas si tu l'as vu dans un auto, peut-être), mais ce n'est pas une bonne idée, car :
- Déjà , ce n'est pas initialement fait pour déclarer des constantes
- Ensuite, on peut mettre un peu n'importe quoi dans un "#define", y compris juste une partie incomplète d'une expression, bref un peu ce qu'on veut, le compilateur ne vérifiera les choses qu'après avoir remplacé le token par le texte correspondant, du coup tu peux un peu injecter n'importe quoi dans ton code sans t'en rendre compte. Exemple:
- Tu perds l'information de type. Et au passage tu perds la vérification du compilateur. Par exemple si pour toi tes valeurs GPxxx sont sensées être des float, le compilateur ne va pas te sortir d'erreur si tu passes par erreur GP72 à une fonction qui prend un int au lieu d'un float, car GP72 sera remplacé par 0 qui est un int valide... et donc ton erreur passera inaperçue et tu ne verras pas le problème (et tu peux perdre des heures à comprendre d'où vient un bug avec ce genre de choses surtout quand c'est marqué derrière une macro #define)
- Puisque ce n'est que du texte recherché/remplacé par le précompilateur, si jamais il y a une erreur de compilation à l'intérieur même de ta macro, cela devient très très vite illisible. Par exemple :
3) La bonne solutionEt encore évidemment là j'ai pris des exemples simples
La bonne façon de déclarer une constante, c'est de la déclarer comme tu ferrais pour une variable, mais avec le mot clé "const" entre le type de la variable et le nom de la variable.
[...La suite dans le prochain post...]
Par exemple : Tu déclares ces lignes dans l'espace global (donc pas à l'intérieur d'une fonction, ni d'une @interface ou @implementation, bref pas à l'intérieur d'accolades mais directement au niveau racine).
Note (très important) que c'est une très mauvaise idée de déclarer des variables globales (donc des variables au niveau racine d'un fichier, hors de tout contexte d'une classe ou d'une fonction), car n'importe qui pourrait modifier ces variables globales n'importe comment, sans protection, et cela peut poser des problèmes (multi-threading, etc, je ne rentrerai pas dans le détail ici). Par contre déclarer des constantes à ce niveau est tout à fait acceptable, et est même la bonne façon de faire.
Il y a cependant quelques petites subtilités, car il y a 2 cas d'usage : des constantes locales à ton fichier (dites "static"), et des constantes globales pour ton application (dites "extern")
1) Constante locale à ton fichier .m
Si tu veux déclarer une constante mais qui ne doit être connue / accessible que dans le fichier .m courant (par exemple appelons-le "MaClasse.m"), et que ces constantes n'ont aucune raison d'être visibles/accessibles depuis les autres fichiers de ton application, alors la constante peut être déclarée dans le fichier .m directement, et le mot clé "static" va permettre de s'assurer que l'on confine cette variable uniquement au fichier courant : Dans ce cas, tu n'as pas à déclarer ces constantes dans le fichier .h, normal puisque tu veux que ces constantes soient uniquement connues de MonFichier.m (et le .h est l'interface publique d'une classe, accessible de l'extérieur, donc si ces constantes doivent être confinées au fichier MonFichier.m elle n'ont pas à apparaà®tre dans son interface publique)
C'est un cas qui n'est pas si rare, par exemple pour les constantes permettant de déclarer des valeurs par défaut pour une classe, ou des constantes utilisées pour un calcul interne à la classe mais qui n'ont aucune raison d'être exposées à l'extérieur (en Programmation Orientée Objet, on préfère faire un maximum d'encapsulation et de n'exposer dans l'interface publique que le strict nécessaire)
2) Constante globale à toute l'application
Si par contre tu veux déclarer une constante qui doit être visible dans toute l'application " et d'après ton exemple ça m'a l'air d'être ton cas " il ne faut pas la déclarer "static", bien au contraire, et il faut déclarer ces constantes dans le .h pour qu'elles soient visibles de tous. Le problème c'est que (1) dans un .h tu ne peux pas donner de valeur à une constante, juste la déclarer " un .h ne contient que les déclaration, pas les valeurs, comme il ne contient que la liste des fonctions, pas leur code " donc il faudra que tu déclares la valeur dans un .m, et (2) si tu déclares la constante dans le .h sans le mot clé "extern", alors à chaque fois que tu vas faire #import "MesConstantes.h" cela va re-déclarer ces constantes une nouvelle fois " il y aura autant de constantes nommées GP90 dans ton code que tu auras fait de #import "Constantes.h" dans ton application, et seule une de ces constantes aura pu avoir sa valeur associée dans le .m, les autres seront vues comme des constantes différentes, ayant certes le même nom mais c'est tout comme si elles en avaient un différent, tu auras créé N constantes nommée GP90...
le mot clé "extern" permet d'éviter cela, en pratique il veut dire "j'informe sur l'honneur le compilateur qu'il existe quelque part une constante avec ce nom, mais c'est tout, ne prévois pas ici d'espace mémoire pour une nouvelle constante, je te dis juste qu'elle existe". Il ne va donc pas créer de constante à chaque fois que tu vas faire le #import, il va juste être mis au courant qu'elle existe. Et c'est dans Constantes.m que tu vas à la fois déclarer ET donner une valeur à ta constante.
Ce qui donne donc, in fine :
Merci AliGator !
Un vrai cours !! j'ai eut beau avoir acheté "développer une application iphone pour les nuls" ce n'est pas aussi clair que ça !!
Je me remet ça ce soir et vous tiens au courant.
Merci encore !
J's'rais d'avis de renommer le topic (Constantes ?) et de le mettre dans la section commune iOS/OSX.
Merci Joanna mais c'est vraiment hard !!
Bonjour,
En relisant ce sujet et la très claire explication d'Aligator je me suis posé une question... qu'en est-il de la question des constantes globales à toute l'application pour Swift ?
Créer un fichier const.swift avec un listing de toutes les contantes sous forme de "let" est-il une solution viable et "propre" ?
Merci d'avance pour vos réponses.
Moi je fais comme ça et c'est viable. Maintenant à savoir si c'est propre je me suis jamais posé la question...
Et qu'en est-il des trucs bien plus complexes.
En raccourcis j'utilise en local dans un .m quelque chose, placé avant l'implémentation, comme:
static struct htmCode{
unichar k ;
char *code ;
} htmlcode[] = {
{34,"quot"}, {38,"amp"}, {60,"lt"}, {62,"gt"} } ;
Et je ne vois pas comment en faire des constantes. La table n'est que lue.
@tablier y a rien de complexe dans ton cas. Tu peux faire la même chose en Swift en déclarant une structure ensuite et un array de structure ou bien un enum avec valeur associées ( suivant la logique de ta structure de données).
Je ne fais pas de swift ici. Ce que j'ai fais marche et pour moi, ce sont des variables. Ce que je ne vois pas, c'est comment en faire des constantes.
Si par "constantes" tu veux que les champs de la struct ne puissent pas être modifiés, il faut déclarer la var struct const:
code[0].code="??";
produit une erreur: assignment of read-only member 'code'
ça marche, merci !