objective c - O que é um typedef enum em Objective-C?




enums (10)

A Apple recomenda definir enums como este desde o Xcode 4.4:

typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Eles também fornecem uma macro prática NS_ENUM:

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

Essas definições fornecem verificação de tipo mais forte e melhor preenchimento de código. Não consegui encontrar uma documentação oficial do NS_ENUM, mas você pode assistir ao vídeo "Modern Objective-C" da sessão WWDC 2012 here .

ATUALIZAÇÃO: Link para documentação oficial here .

Eu não acho que eu fundamentalmente entenda o que é um enum e quando usá-lo.

Por exemplo:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

O que realmente está sendo declarado aqui?


Enum é um tipo de dados definido pelo usuário. TIPOS DE DADOS ENUMERADOS Variáveis ​​de tipo de dados enumerados só podem assumir valores que foram previamente declarados.

enum month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
enum month this_month;

this_month = feb;

Na declaração acima, mês é declarado como um tipo de dados enumerados. Consiste em um conjunto de valores, jan a dez. Numericamente, jan recebe o valor 1, feb o valor 2 e assim por diante.

A variável this_month é declarada como sendo do mesmo tipo do mês, então é atribuído o valor associado ao feb. This_month não pode ser atribuído a nenhum valor além daqueles especificados na lista de inicialização para a declaração do mês.


O enum (abreviação de enumeração) é usado para enumerar um conjunto de valores (enumeradores). Um valor é qualquer coisa abstrata representada por um símbolo (uma palavra). Por exemplo, um enum básico pode ser

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };

Esse enum é chamado anônimo porque você não tem um símbolo para nomeá-lo. Mas ainda está perfeitamente correto. Basta usá-lo assim

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;

Está bem. A vida é linda e tudo corre bem. Mas um dia você precisa reutilizar esse enum para definir uma nova variável para armazenar myGrandFatherPantSize e, em seguida, escreve:

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;

Mas então você tem um erro de compilador "redefinição do enumerador". Na verdade, o problema é que o compilador não tem certeza de que você primeiro enum e seu segundo descrevem a mesma coisa.

Então, se você quiser reutilizar o mesmo conjunto de enumeradores (aqui xs ... xxxxl) em vários lugares, você deve marcá-lo com um nome exclusivo. Na segunda vez que você usar esse conjunto, basta usar a tag. Mas não se esqueça de que essa tag não substitui a palavra enum, mas apenas o conjunto de enumeradores. Então, tome cuidado para usar o enum como de costume. Como isso:

// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize; 
// here the second use of my enum. It works now !
enum sizes myGrandFatherPantSize;

você pode usá-lo em uma definição de parâmetro também:

// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;

Você poderia dizer que reescrever o enum em todos os lugares não é conveniente e faz o código parecer um pouco estranho. Você está certo. Um tipo real seria melhor.

Este é o passo final da nossa grande progressão para a cimeira. Apenas adicionando um typedef, vamos transformar nosso enum em um tipo real. Ah, uma última coisa, typedef não é permitido dentro de sua classe. Em seguida, defina seu tipo logo acima. Faça isso deste modo:

// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

@interface myClass {
   ...
   size_type myGrandMotherDressSize, myGrandFatherPantSize;
   ...
}

Lembre-se de que a tag é opcional. Então, desde aqui, nesse caso, não marcamos os enumeradores, mas apenas para definir um novo tipo. Então nós realmente não precisamos mais disso.

// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;

@interface myClass : NSObject {
  ...
  size_type myGrandMotherDressSize, myGrandFatherPantSize;
  ...
}
@end

Se você está desenvolvendo em ObjectiveC com XCode, eu deixo você descobrir algumas macros boas prefixadas com NS_ENUM. Isso deve ajudá-lo a definir bons enums facilmente e, além disso, ajudará o analisador estático a fazer algumas verificações interessantes antes de compilar.

Bom Enum!


Três coisas estão sendo declaradas aqui: um tipo anônimo enumerado é declarado, ShapeType está sendo declarado como typedef para essa enumeração anônima e os três nomes kCircle , kRectangle e kOblateSpheroid estão sendo declarados como constantes integrais.

Vamos quebrar isso. No caso mais simples, uma enumeração pode ser declarada como

enum tagname { ... };

Isso declara uma enumeração com o tag tagname . Em C e Objective-C (mas não em C ++), qualquer referência a isso deve ser precedida pela palavra-chave enum . Por exemplo:

enum tagname x;  // declare x of type 'enum tagname'
tagname x;  // ERROR in C/Objective-C, OK in C++

Para evitar ter que usar a palavra-chave enum todos os lugares, um typedef pode ser criado:

enum tagname { ... };
typedef enum tagname tagname;  // declare 'tagname' as a typedef for 'enum tagname'

Isso pode ser simplificado em uma linha:

typedef enum tagname { ... } tagname;  // declare both 'enum tagname' and 'tagname'

E, finalmente, se não precisarmos usar o enum tagname com a palavra-chave enum , podemos tornar a enum anônima e apenas declará-la com o nome typedef:

typedef enum { ... } tagname;

Agora, nesse caso, estamos declarando que o ShapeType é um nome de typedef de uma enumeração anônima. ShapeType é realmente apenas um tipo integral e deve ser usado apenas para declarar variáveis ​​que contêm um dos valores listados na declaração (isto é, um dos kCircle , kRectangle e kOblateSpheroid ). Você pode atribuir um outro valor a uma variável ShapeType , por isso deve ter cuidado ao ler os valores de enum.

Finalmente, kCircle , kRectangle e kOblateSpheroid são declarados como constantes integrais no namespace global. Como nenhum valor específico foi especificado, eles são atribuídos a inteiros consecutivos começando com 0, então kCircle é 0, kRectangle é 1 e kOblateSpheroid é 2.


Um tipo definido pelo usuário que possui os valores possíveis de kCircle , kRectangle ou kOblateSpheroid . Os valores dentro do enum (kCircle, etc) são visíveis fora do enum, no entanto. É importante ter isso em mente ( int i = kCircle; é válido, por exemplo).


Um typedef permite que o programador defina um tipo Objective-C como outro. Por exemplo,

typedef int Counter; define o tipo Counter para ser equivalente ao tipo int. Isso melhora drasticamente a legibilidade do código.


enum é usado para atribuir valor a elementos enum que não podem ser feitos em struct. Então, toda vez, em vez de acessar a variável completa, podemos fazer isso pelo valor que atribuímos às variáveis ​​em enum. Por padrão, ele começa com atribuição 0, mas podemos atribuir a ele qualquer valor e a próxima variável no enum receberá um valor do valor anterior +1.


enum pode reduzir muitos tipos de "erros" e tornar o código mais gerenciável

#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER

A definição não tem restrições. É simplesmente apenas uma substituição. Não é capaz de limitar todas as condições do estado. Quando o STATE é atribuído a 5, o programa estará errado, porque não há estado correspondente. Mas o compilador não vai avisar STATE = 5

Então é melhor usar assim

typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

SampleState state = SampleStateGood;

Atualização para alteração de 64 bits: de acordo com documentos da Apple sobre alterações de 64 bits,

Enumerações também são digitadas: No compilador LLVM, tipos enumerados podem definir o tamanho da enumeração. Isso significa que alguns tipos enumerados também podem ter um tamanho maior do que o esperado. A solução, como em todos os outros casos, é não fazer suposições sobre o tamanho de um tipo de dados. Em vez disso, atribua quaisquer valores enumerados a uma variável com o tipo de dados adequado

Então você tem que criar enum com o tipo abaixo da sintaxe se você suporta 64 bits.

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

ou

typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;

Caso contrário, ele levará a um aviso, pois a Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

Atualização para programação rápida:

Em rápida, há uma mudança de sintaxe.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }

typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

então você pode usá-lo como: -

 ShapeType shape;

e

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

agora você pode usá-lo como: -

enum ShapeType shape;




typedef