objective-c - objective c functions
Constantes en Objective-C (13)
Como dijo Abizer, podrías ponerlo en el archivo PCH. Otra forma que no está tan sucia es crear un archivo de inclusión para todas sus claves y luego incluirlo en el archivo en el que está utilizando las claves, o incluirlo en el PCH. Con ellos en su propio archivo de inclusión, que al menos te da un lugar para buscar y definir todas estas constantes.
Estoy desarrollando una aplicación Cocoa , y estoy usando NSString
constantes como formas de almacenar nombres de clave para mis preferencias.
Entiendo que es una buena idea, ya que permite cambiar las teclas fácilmente si es necesario. Además, es todo el concepto de ''separar sus datos de su lógica''.
De todos modos, ¿hay una buena manera de definir estas constantes una vez para toda la aplicación? Estoy seguro de que hay una forma fácil e inteligente, pero en este momento mis clases simplemente redefinen las que usan.
Debe crear un archivo de encabezado como
// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.
(puede usar extern
lugar de FOUNDATION_EXPORT
si su código no se usará en entornos mixtos C / C ++ o en otras plataformas)
Puede incluir este archivo en cada archivo que use las constantes o en el encabezado precompilado para el proyecto.
Estas constantes se definen en un archivo .m como
// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";
Se deben agregar constantes.m al objetivo de su aplicación / marco para que esté vinculado al producto final.
La ventaja de usar constantes de cadena en lugar de constantes de #define
''d es que puede probar la igualdad mediante la comparación de punteros ( stringInstance == MyFirstConstant
), que es mucho más rápida que la comparación de cadenas ( [stringInstance isEqualToString:MyFirstConstant]
) (y más fácil de leer, IMO).
Generalmente estoy usando la forma publicada por Barry Wark y Rahul Gupta.
Sin embargo, no me gusta repetir las mismas palabras en los archivos .h y .m. Tenga en cuenta que en el siguiente ejemplo, la línea es casi idéntica en ambos archivos:
// file.h
extern NSString* const MyConst;
//file.m
NSString* const MyConst = @"Lorem ipsum";
Por lo tanto, lo que me gusta hacer es usar alguna maquinaria de preprocesador de C. Déjame explicarte a través del ejemplo.
Tengo un archivo de encabezado que define 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
En mi par de .h / .m donde quiero definir la constante, hago lo siguiente:
// myfile.h
#import <StringConsts.h>
STR_CONST(MyConst, "Lorem Ipsum");
STR_CONST(MyOtherConst, "Hello world");
// myfile.m
#define SYNTHESIZE_CONSTS
#import "myfile.h"
y listo, tengo toda la información sobre las constantes en el archivo .h solamente.
La manera más fácil:
// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"
Mejor manera:
// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;
// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";
Una de las ventajas de la segunda es que cambiar el valor de una constante no causa una reconstrucción de todo el programa.
La respuesta aceptada (y correcta) dice que "puede incluir este archivo [Constants.h] ... en el encabezado precompilado del proyecto".
Como novato, tuve dificultades para hacer esto sin más explicaciones: a continuación se explica cómo: en su archivo YourAppNameHere-Prefix.pch (este es el nombre predeterminado para el encabezado precompilado en Xcode), importe su Constants.h dentro del bloque #ifdef __OBJC__
.
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "Constants.h"
#endif
También tenga en cuenta que los archivos Constants.h y Constants.m no deben contener absolutamente nada más, excepto lo que se describe en la respuesta aceptada. (Sin interfaz o implementación).
Si le gusta la constante de espacio de nombres, puede aprovechar la estructura, viernes Preguntas y respuestas 2011-08-19: Constantes y funciones del espacio de nombres
// 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"
};
Si quieres algo como constantes globales; Una forma rápida y sucia es colocar las declaraciones constantes en el archivo pch
.
También hay una cosa que mencionar. Si necesita una constante no global, debe usar una palabra clave static
.
Ejemplo
// In your *.m file
static NSString * const kNSStringConst = @"const value";
Debido a la palabra clave static
, esta constante no es visible fuera del archivo.
Corrección menor por @QuinnTaylor : las variables estáticas son visibles dentro de una unidad de compilación . Por lo general, este es un solo archivo .m (como en este ejemplo), pero puede morderlo si lo declara en un encabezado que se incluye en otro lugar, ya que obtendrá errores del enlazador después de la compilación
Trate de usar un método de clase:
+(NSString*)theMainTitle
{
return @"Hello World";
}
Lo uso a veces.
Una ligera modificación de la sugerencia de @Krizz, para que funcione correctamente si el archivo de encabezado de constantes se incluye en el PCH, que es bastante normal. Dado que el original se importa al PCH, no lo volverá a cargar en el archivo .m
, por lo que no obtendrá ningún símbolo y el vinculador no estará satisfecho.
Sin embargo, la siguiente modificación le permite trabajar. Es un poco complicado, pero funciona.
Necesitará 3 archivos, el archivo .h
que tiene las definiciones constantes, el archivo .h
y el archivo .m
, .m
ConstantList.h
, Constants.h
y Constants.m
, respectivamente. Los contenidos de Constants.h
son simplemente:
// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"
y el archivo Constants.m
ve como:
// Constants.m
#ifdef STR_CONST
#undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"
Finalmente, el archivo ConstantList.h
tiene las declaraciones reales en él y eso es todo:
// ConstantList.h
STR_CONST(kMyConstant, "Value");
…
Un par de cosas a anotar:
Tuve que redefinir la macro en el archivo
.m
después de#undef
ing para que se use la macro.También tuve que usar
#include
lugar de#import
para que esto funcione correctamente y evitar que el compilador vea los valores precompilados previamente.Esto requerirá una recompilación de su PCH (y probablemente de todo el proyecto) cada vez que se modifique algún valor, lo cual no es el caso si se separan (y duplican) de manera normal.
Espero que sea de ayuda para alguien.
Utilizo una clase de singleton, para poder burlarme de la clase y cambiar las constantes si es necesario para la prueba. La clase de constantes se ve así:
#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
Y se usa de esta manera (tenga en cuenta el uso de una abreviatura para las constantes c - se guarda escribiendo [[Constants alloc] init]
cada vez):
#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
Yo mismo tengo un encabezado dedicado a declarar las NSStrings constantes utilizadas para las preferencias, como así:
extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;
Luego declarándolos en el archivo .m adjunto:
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";
Este enfoque me ha servido bien.
Edición: tenga en cuenta que esto funciona mejor si las cadenas se utilizan en varios archivos. Si solo un archivo lo usa, simplemente puede hacer #define kNSStringConstant @"Constant NSString"
en el archivo .m que usa la cadena.
// Prefs.h
extern NSString * const RAHUL;
// Prefs.m
NSString * const RAHUL = @"rahul";