Qual é a melhor maneira de criar constantes no Objective-C

156

Estou criando um cliente Reddit para fins de aprendizado. Eu preciso ter um arquivo com constantes nele. Eu estava pensando em importar o arquivo no Reddit-Prefix.pcharquivo para disponibilizar as constantes para todos os arquivos. É uma boa maneira de fazer as coisas? Além disso, fiz minha pesquisa e encontrei vários métodos para criar constantes, mas não sei qual usar:

  • #define macro
  • const
  • static const
  • extern const
  • enum

Então, qual o caminho preferido? Qual é a convenção? Eu sei que "depende", mas minha pergunta é mais específica: quais são os casos de uso para cada uma dessas soluções?

Além disso, se estiver usando extern const, preciso importar o arquivo ou as constantes estarão disponíveis globalmente sem importar o arquivo?

Uma coisa que eu poderia concluir logicamente é que enumé a melhor escolha ao definir algo como domínios de erro personalizados (estou realmente certo?). Mas e os outros?

Robert Audi
fonte
stackoverflow.com/questions/11153156/…, por favor visite este link ... sua solução está neste post
User 1531343
3
@BhavikKama: Essa é uma pergunta mais restrita, contrastando duas soluções específicas.
precisa saber é o seguinte
for - static const, #define, enum, este link é útil stackoverflow.com/questions/1674032/static-const-vs-define-in-c que fornece uma boa explicação sobre essas 3 alternativas de const
User 1531343
enumé útil apenas para valores integrais. #definee constantes podem ser qualquer tipo de dados.
rmaddy
const,, static conste extern constsão todos iguais, exceto no escopo. Portanto, existem realmente apenas três opções.
rmaddy

Respostas:

385

A primeira pergunta é qual o escopo que você deseja que suas constantes tenham, que são realmente duas perguntas:

  • Essas constantes são específicas para uma única classe ou faz sentido tê-las em todo o aplicativo?
  • Se eles são específicos da classe, devem ser usados ​​pelos clientes da classe ou apenas dentro da classe?

Se eles são específicos e internos a uma única classe, declare-os como static constna parte superior do arquivo .m, da seguinte maneira:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Se eles pertencem a uma única classe, mas devem ser públicos / usados ​​por outras classes, declare-os como externno cabeçalho e defina-os no .m:

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Se eles devem ser globais, declare-os em um cabeçalho e defina-os em um módulo correspondente, especificamente para essas constantes.

Você pode misturá-las e combiná-las para diferentes constantes com diferentes níveis de quão global você deseja que sejam e para diferentes constantes globais que simplesmente não pertencem juntas - você pode colocá-las em módulos separados, cada um com seu próprio cabeçalho, se você quer.

Por que não #define?

A resposta antiga é “macros não possuem informações de tipo”, mas hoje os compiladores são bastante inteligentes em fazer toda a verificação de tipos de literais (para os quais as macros se expandem) e também de variáveis.

A resposta moderna é porque o depurador não saberá sobre suas macros. Você não pode dizer [myThing addObserver:self forKey:MyThingNotificationKey]em um comando debugger se MyThingNotificationKeyé uma macro; o depurador só pode saber se for uma variável.

Por que não enum?

Bem, rmaddy me venceu nos comentários: enumsó pode definir constantes inteiras. Coisas como números de identificação serial, máscaras de bits, códigos de quatro bytes, etc.

Para esses fins, enumé ótimo e você absolutamente deve usá-lo. (Melhor ainda, use as teclas NS_ENUMeNS_OPTIONS .) Para outras coisas, você deve usar outra coisa; enumnão faz nada além de números inteiros.

E outras perguntas

Eu estava pensando em importar o arquivo no arquivo Reddit-Prefix.pch para disponibilizar as constantes para todos os arquivos. É uma boa maneira de fazer as coisas?

Provavelmente inofensivo, mas provavelmente excessivo. Importe os cabeçalhos das constantes para onde precisar deles.

Quais são os casos de uso para cada uma dessas soluções?

  • #define: Bastante limitado. Sinceramente, não tenho certeza de que exista uma boa razão para usar isso para constantes.
  • const: Melhor para constantes locais. Além disso, você deve usar isso para o que você declarou em um cabeçalho e agora está definindo.
  • static const: Melhor para constantes específicas de arquivo (ou classe).
  • extern const: Você deve usar isso ao exportar uma constante em um cabeçalho.

Além disso, se estiver usando extern const, preciso importar o arquivo ou as constantes estarão disponíveis globalmente sem importar o arquivo?

Você precisa importar o arquivo, em cada arquivo em que o usa ou no cabeçalho do prefixo.

Peter Hosey
fonte
3
Por que não usar static NSString *consto .harquivo completamente?
Iulian Onofrei 8/11
3
@IulianOnofrei: Você pode, se estiver em um aplicativo e não em um framework. Se você o fizer static NSString *const foo = @"foo";, seu cabeçalho determinará qual é a string e deve ser a mesma em todos os lugares - se você alterar a string e diferentes partes usarem versões diferentes do cabeçalho com uma string diferente, as strings não corresponderão na execução Tempo. Em uma estrutura, você deseja fornecer acesso apenas ao símbolo e permitir que a estrutura seja a única fonte do verdadeiro valor desse símbolo, para que todos obtenham a mesma string em um só lugar. Isso é o que externvocê recebe.
Peter Hosey
Observação adicional sobre #defines: não é garantido que eles tenham o mesmo endereço na memória (dependendo de como são declarados, eles podem alocar uma nova instância toda vez que são usados); portanto, o uso myObject == MyDefinenem sempre funciona como o esperado, mas myObject == MyStaticConstvai.
Ben Leggiero
Faz sentido soletrar como em static NSString *constvez de static NSString const*?? Alguma diferença ?!
kokos8998
@ kokos8998 isso faz alguma diferença? Sim. static NSString const *é o mesmo que static const NSString *e significa "um ponteiro (mutável) para um NSString constante" - que é um pouco inútil aqui, já que o NSString já é imutável. O que você deseja apenas static NSString * const- que é um "ponteiro constante para um NSString"
David
8

FOUNDATION_EXPORT

Considere usar FOUNDATION_EXPORTum pouco mais de compatibilidade do externque é definido na base e compila em formatos compatíveis para C, C ++ e Win32.

Conforme definido em NSObjCRuntime.h

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif
Steve Moser
fonte