Les constantes dans L'objectif-C

je développe une application Cocoa , et j'utilise constant NSString s comme moyen de stocker des noms clés pour mes préférences.

je comprends que c'est une bonne idée, car cela permet de changer facilement les clés si nécessaire. De plus, c'est la notion de "séparer vos données de votre logique".

de toute façon, y a-t-il un bon moyen de définir ces constantes une seule fois pour l'ensemble de l'application? Je suis sûr qu'il y a un moyen facile et de façon intelligente, mais en ce moment, mes cours redéfinissent ceux qu'ils utilisent.

974
demandé sur Peter Mortensen 2009-02-12 00:52:02

13 réponses

vous devez créer un fichier d'en-tête comme

// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.

(vous pouvez utiliser extern au lieu de FOUNDATION_EXPORT si votre code ne sera pas utilisé dans des environnements mixtes c/c++ ou sur d'autres plateformes)

, Vous pouvez inclure ce fichier dans chaque fichier qui utilise les constantes ou dans l'en-tête précompilé pour le projet.

vous définissez ces constantes en a.m fichier comme

// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";

constantes.m être ajouté à l'objectif de votre application / cadre de sorte qu'il soit lié au produit final.

l'avantage d'utiliser des constantes de chaîne au lieu de #define 'd constantes est que vous pouvez tester pour l'égalité en utilisant la comparaison de pointeur ( stringInstance == MyFirstConstant ) qui est beaucoup plus rapide que la comparaison de chaîne ( [stringInstance isEqualToString:MyFirstConstant] ) (et plus facile à lire, IMO).

1249
répondu Barry Wark 2013-04-29 11:31:38

voie la plus facile:

// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"

Meilleure façon:

// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;

// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";

un avantage de la seconde est que changer la valeur d'une constante ne provoque pas une reconstruction de votre programme entier.

264
répondu Andrew Grant 2009-02-11 22:42:14

Il y a aussi une chose à mentionner. Si vous avez besoin d'une constante Non globale, vous devez utiliser le mot-clé static .

exemple

// In your *.m file
static NSString * const kNSStringConst = @"const value";

à cause du mot-clé static , cette const n'est pas visible à l'extérieur du fichier.


Correction mineure par @QuinnTaylor : les variables statiques sont visibles dans une compilation l'unité . Généralement, c'est une seule .m fichier (comme dans cet exemple), mais il peut vous mordre si vous le déclarez dans un en-tête qui est inclus ailleurs, puisque vous obtiendrez des erreurs de linker après compilation

182
répondu kompozer 2017-05-23 12:10:26

la réponse acceptée (et correcte) dit que" vous pouvez inclure ceci [constantes.h] fichier... dans l'en-tête précompilé pour le projet."

en tant que novice, j'ai eu de la difficulté à le faire sans autre explication -- voici comment: dans votre préfixe Yerrappnamehere.fichier pch (c'est le nom par défaut de l'en-tête précompilé dans Xcode), importez vos constantes.h à l'intérieur du #ifdef __OBJC__ bloc .

#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
  #import "Constants.h"
#endif

Note complémentaire que les Constantes.h et constantes.les fichiers m ne doivent contenir absolument rien d'autre que ce qui est décrit dans la réponse acceptée. (Pas d'interface ou de mise en œuvre).

117
répondu Victor Van Hee 2016-01-31 17:56:33

j'utilise généralement le chemin posté par Barry Wark et Rahul Gupta.

bien que, je n'aime pas répéter les mêmes mots dans les deux .h et .m de fichier. Notez que dans l'exemple suivant, la ligne est presque identique dans les deux fichiers:

// file.h
extern NSString* const MyConst;

//file.m
NSString* const MyConst = @"Lorem ipsum";

par conséquent, ce que j'aime faire est d'utiliser des machines préprocesseur C. Je m'explique par l'exemple.

j'ai un fichier d'en-tête qui définit la macro STR_CONST(name, value) :

// StringConsts.h
#ifdef SYNTHESIZE_CONSTS
# define STR_CONST(name, value) NSString* const name = @ value
#else
# define STR_CONST(name, value) extern NSString* const name
#endif

Le dans mon .h./m paire où je veux définir la constante je fais ce qui suit:

// myfile.h
#import <StringConsts.h>

STR_CONST(MyConst, "Lorem Ipsum");
STR_CONST(MyOtherConst, "Hello world");

// myfile.m
#define SYNTHESIZE_CONSTS
#import "myfile.h"

et voilà, j'ai toutes les informations sur les constantes .h seulement.

50
répondu Krizz 2012-01-06 01:17:37

une légère modification de la suggestion de @Krizz, de sorte qu'elle fonctionne correctement si le fichier d'en-tête constantes doit être inclus dans le PCH, ce qui est assez normal. Puisque L'original est importé dans le PCH, il ne sera pas rechargé dans le fichier .m et donc vous ne recevez aucun symbole et le linker est malheureux.

cependant, la modification suivante lui permet de fonctionner. C'est un peu compliqué, mais ça marche.

Vous aurez besoin de 3 fichiers", 151940920" fichier qui a les définitions de constantes, le .h et le .m du fichier, je vais utiliser ConstantList.h , Constants.h et Constants.m , respectivement. le contenu de Constants.h est simplement:

// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"

et le fichier Constants.m ressemble à:

// Constants.m
#ifdef STR_CONST
    #undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"

enfin, le fichier ConstantList.h contient les déclarations réelles et c'est tout:

// ConstantList.h
STR_CONST(kMyConstant, "Value");
…

deux choses à noter:

  1. j'ai dû redéfinir la macro dans la .m fichier après #undef ing pour la macro à utiliser.

  2. j'ai aussi dû utiliser #include au lieu de #import pour que cela fonctionne correctement et pour éviter que le compilateur voit les valeurs précompilées.

  3. pour ce faire, il vous faudra recompiler votre PCH (et probablement l'ensemble du projet) chaque fois que des valeurs sont modifiées, ce qui n'est pas le cas si elles sont séparées (et dupliquées) comme d'habitude.

l'Espérance qui est utile pour quelqu'un.

25
répondu Scott Little 2011-12-03 00:03:57

j'ai moi-même un en-tête dédié à la déclaration constante NSStrings utilisés pour les préférences comme cela:

extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;

puis les déclarer dans l'accompagnement .m fichier:

NSString * const PPRememberMusicList = @"Remember Music List";
NSString * const PPLoadMusicAtListLoad = @"Load music when loading list";
NSString * const PPAfterPlayingMusic = @"After playing music";
NSString * const PPGotoStartupAfterPlaying = @"Go to startup pos. after playing";

Cette approche m'a bien servi.

Edit: Notez que cela fonctionne mieux si les chaînes sont utilisées dans plusieurs fichiers. Si un seul fichier l'utilise, Vous pouvez simplement faire #define kNSStringConstant @"Constant NSString" dans le .m de fichier qui utilise la chaîne.

25
répondu MaddTheSane 2013-08-26 04:22:08
// Prefs.h
extern NSString * const RAHUL;

// Prefs.m
NSString * const RAHUL = @"rahul";
14
répondu rahul gupta 2011-09-28 16:19:44

comme Abizer l'a dit, Vous pouvez le mettre dans le dossier de PCH. Une autre façon qui n'est pas si sale est de faire un fichier include pour toutes vos clés et puis soit inclure que dans le fichier que vous utilisez les clés dans, ou, l'inclure dans le PCH. Avec eux dans leur propre fichier include, cela vous donne au moins un endroit pour chercher et définir toutes ces constantes.

12
répondu Grant Limberg 2009-02-11 22:05:55

si vous voulez quelque chose comme les constantes globales; un moyen rapide et sale est de mettre les déclarations constantes dans le fichier pch .

11
répondu Abizern 2017-01-07 09:04:36

j'utilise une classe singleton, de sorte que je puisse me moquer de la classe et changer les constantes si nécessaire pour tester. La classe des constantes ressemble à ceci:

#import <Foundation/Foundation.h>

@interface iCode_Framework : NSObject

@property (readonly, nonatomic) unsigned int iBufCapacity;
@property (readonly, nonatomic) unsigned int iPort;
@property (readonly, nonatomic) NSString * urlStr;

@end

#import "iCode_Framework.h"

static iCode_Framework * instance;

@implementation iCode_Framework

@dynamic iBufCapacity;
@dynamic iPort;
@dynamic urlStr;

- (unsigned int)iBufCapacity
{
    return 1024u;
};

- (unsigned int)iPort
{
    return 1978u;
};

- (NSString *)urlStr
{
    return @"localhost";
};

+ (void)initialize
{
    if (!instance) {
        instance = [[super allocWithZone:NULL] init];
    }
}

+ (id)allocWithZone:(NSZone * const)notUsed
{
    return instance;
}

@end

et il est utilisé comme ceci (notez l'utilisation d'un raccourci pour les constantes C - IT sauve Dactylographie [[Constants alloc] init] à chaque fois):

#import "iCode_FrameworkTests.h"
#import "iCode_Framework.h"

static iCode_Framework * c; // Shorthand

@implementation iCode_FrameworkTests

+ (void)initialize
{
    c  = [[iCode_Framework alloc] init]; // Used like normal class; easy to mock!
}

- (void)testSingleton
{
    STAssertNotNil(c, nil);
    STAssertEqualObjects(c, [iCode_Framework alloc], nil);
    STAssertEquals(c.iBufCapacity, 1024u, nil);
}

@end
7
répondu Howard Lovatt 2012-07-16 00:00:35

Essayez d'utiliser une méthode de classe:

+(NSString*)theMainTitle
{
    return @"Hello World";
}

je l'utilise parfois.

7
répondu groumpf 2016-01-31 17:55:33

si vous aimez namespace constant, vous pouvez utiliser struct, Friday Q & A 2011-08-19: namespaced Constants and Functions

// in the header
extern const struct MANotifyingArrayNotificationsStruct
{
    NSString *didAddObject;
    NSString *didChangeObject;
    NSString *didRemoveObject;
} MANotifyingArrayNotifications;

// in the implementation
const struct MANotifyingArrayNotificationsStruct MANotifyingArrayNotifications = {
    .didAddObject = @"didAddObject",
    .didChangeObject = @"didChangeObject",
    .didRemoveObject = @"didRemoveObject"
};
7
répondu onmyway133 2016-08-12 11:54:11