objective c - Costanti in Objective-C




cocoa constants (9)

Sto sviluppando un'applicazione Cocoa e sto usando costante NSString come modi per memorizzare i nomi dei tasti per le mie preferenze.

Capisco che sia una buona idea, perché consente di cambiare facilmente le chiavi se necessario. Inoltre, è l'intera nozione "separa i tuoi dati dalla tua logica".

Ad ogni modo, c'è un buon modo per definire queste costanti una volta per l'intera applicazione? Sono sicuro che c'è un modo semplice e intelligente, ma in questo momento le mie classi ridefiniscono quelle che usano.


C'è anche una cosa da ricordare. Se hai bisogno di una costante non globale, dovresti usare static parola chiave static .

Esempio

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

A causa della parola chiave static , questo const non è visibile al di fuori del file.

Correzione secondaria di @QuinnTaylor : le variabili statiche sono visibili all'interno di un'unità di compilazione . Di solito, questo è un singolo file .m (come in questo esempio), ma può morderti se lo dichiari in un'intestazione che è inclusa altrove, dal momento che otterrai errori di linker dopo la compilazione


Come ha detto Abizer, potresti inserirlo nel file PCH. Un altro modo che non è così sporco è quello di creare un file include per tutte le tue chiavi e quindi includerlo nel file in cui stai usando le chiavi o includerlo nel PCH. Con loro nel proprio file di inclusione, questo ti dà almeno un posto dove cercare e definire tutte queste costanti.


Il modo più semplice:

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

Modo migliore:

// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;

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

Un vantaggio del secondo è che la modifica del valore di una costante non causa una ricostruzione dell'intero programma.


In genere sto usando il modo pubblicato da Barry Wark e Rahul Gupta.

Anche se, non mi piace ripetere le stesse parole in entrambi i file .h e .m. Nota che nel seguente esempio la linea è quasi identica in entrambi i file:

// file.h
extern NSString* const MyConst;

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

Pertanto, ciò che mi piace fare è usare alcuni macchinari per il preprocessore C. Lasciatemi spiegare attraverso l'esempio.

Ho un file di intestazione che definisce 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

La mia coppia .h / .m dove voglio definire la costante faccio quanto segue:

// 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à, ho tutte le informazioni sulle costanti nel file .h solo.


Io uso una classe singleton, in modo che io possa prendere in giro la classe e modificare le costanti se necessario per il test. La classe delle costanti ha questo aspetto:

#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

Ed è usato in questo modo (si noti l'uso di una scorciatoia per le costanti c - salva ogni volta la digitazione [[Constants alloc] init] ):

#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

La risposta accettata (e corretta) dice che "puoi includere questo file [Constants.h] ... nell'intestazione precompilata per il progetto."

Come novizio, ho avuto difficoltà a fare questo senza ulteriori spiegazioni - ecco come: Nel tuo file YourAppNameHere-Prefix.pch (questo è il nome predefinito per l'intestazione precompilata in Xcode), importa il tuo Constants.h all'interno del blocco #ifdef __OBJC__ .

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

Si noti inoltre che i file Constants.h e Constants.m non devono contenere assolutamente nient'altro in essi ad eccezione di quanto descritto nella risposta accettata. (Nessuna interfaccia o implementazione).


Se ti piace la costante dello spazio dei nomi, puoi sfruttare la struttura, venerdì Q & A 2011-08-19: Costanti e funzioni con spazi dei nomi

// 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"
};

Se vuoi qualcosa come le costanti globali; un modo un po 'veloce è mettere le dichiarazioni costanti nel file pch .


// Prefs.h
extern NSString * const RAHUL;

// Prefs.m
NSString * const RAHUL = @"rahul";




constants