O que é um enum typedef no Objective-C?

1087

Acho que não entendo fundamentalmente o que enumé e quando usá-lo.

Por exemplo:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

O que realmente está sendo declarado aqui?

Craig
fonte
2
O tipo definido pelo usuário é chamado "enum"? Era o que eu pensava, até encontrar um código com várias declarações de typedef enum.
Craig
8
Não, o tipo definido pelo usuário é ShapeType. Leia sobre o typedef: en.wikipedia.org/wiki/Typedef
rampion
6
Um typedef no Objective-C é exatamente igual a um typedef em C. E uma enumeração no Objective-C é exatamente igual a um enum em C. Isso declara um enum com três constantes kCircle = 0, kRectangle = 1 e kOblateSpheroid = 2 e fornece ao tipo de enum o nome ShapeType. Se você não sabe o que "typedef" e significa "enumeração", comprar um livro sobre C.
gnasher729

Respostas:

1565

Três coisas estão sendo declarada aqui: um tipo enumerado anônimo é declarada, ShapeTypeestá sendo declarado um typedef para essa enumeração anônima, e os três nomes kCircle, kRectanglee kOblateSpheroidestão sendo declarados como constantes integral.

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

enum tagname { ... };

Isso declara uma enumeração com a tag tagname. Em C e Objective-C (mas não em C ++), qualquer referência a isso deve ser precedida com a enumpalavra - chave. 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 enumpalavra - chave em qualquer lugar, 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 enum tagnamea enumpalavra - chave, podemos tornar o enumanônimo e apenas declará-lo com o nome typedef:

typedef enum { ... } tagname;

Agora, neste caso, estamos declarando ShapeTypeser um nome digitado com digitação de uma enumeração anônima. ShapeTypeé realmente apenas um tipo integral, e só deve ser usado para declarar variáveis que possuem um dos valores listados na declaração (isto é, um dos kCircle, kRectanglee kOblateSpheroid). ShapeTypePorém, você pode atribuir outro valor a uma variável lançando, portanto, tenha cuidado ao ler valores de enumeração.

Finalmente, kCircle, kRectangle, e kOblateSpheroidsão declarados como constantes integral no espaço de nomes global. Como nenhum valor específico foi especificado, eles são atribuídos a números inteiros consecutivos começando com 0, então kCircleé 0, kRectangleé 1 e kOblateSpheroidé 2.

Adam Rosenfield
fonte
6
Boa explicação - apenas para adicionar uma coisa, o struct segue regras de nomenclatura semelhantes em C (não tenho certeza sobre o Objective-C).
227 Michael Burr
109
Objective-C é um superconjunto apropriado de C. Todas as regras de nomenclatura C struct em C são igualmente válidas em Objective-C.
sigjuice
Impressionante. Posso apenas usar C ++ enum estilo e também não precisa escrever enum :)
user4951
11
Você pode usar enumerações no estilo C ++ se o arquivo no qual você as declarar for um arquivo .mm em vez de um .m. Objective-C ++ é absurdamente poderoso.
21711 Kevin Murray
14
E depois que você tiver resolvido essa resposta, vale a pena examinar os novos NS_ENUM e NS_OPTIONS. Tutorial aqui: nshipster.com/ns_enum-ns_options e SO aqui: stackoverflow.com/questions/14080750/…
Snowcrash
254

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 útil NS_ENUM:

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

Essas definições fornecem verificação de tipo mais forte e melhor conclusão de código. Não consegui encontrar a documentação oficial NS_ENUM, mas você pode assistir ao vídeo "Objetivo Moderno-C" da sessão da WWDC 2012 aqui .


ATUALIZAÇÃO
Link para a documentação oficial aqui .

Vladimir Grigorov
fonte
13
A parte sobre "Enum Improvements" começa em 5:58
vikingosegundo
5
Como comentado em outra resposta, veja explicação da Apple NS_ENUMmacro por NSHipster: NSHipster.com/ns_enum-ns_options
Basil Bourque
1
Este é o link para a documentação oficial sobre NS_ENUM: developer.apple.com/library/ios/releasenotes/ObjectiveC/…
YoGiN
50

Uma enum declara um conjunto de valores ordenados - o typedef apenas adiciona um nome útil a isso. O primeiro elemento é 0, etc.

typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;

O acima é apenas uma enumeração de tags shapeType.

hburde
fonte
34

Um tipo definido de utilizador que tem os valores possíveis de kCircle, kRectangle, ou kOblateSpheroid. Os valores dentro da enumeração (kCircle, etc) são visíveis fora da enumeração. É importante ter isso em mente ( int i = kCircle;é válido, por exemplo).

Brian Mitchell
fonte
30

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

As enumerações também são digitadas: No compilador LLVM, os 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 apropriado

Portanto, você deve criar um enum com o tipo abaixo da sintaxe, se for compatível com 64 bits.

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

ou

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

Caso contrário, levará ao aviso como Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

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

No Swift, há uma alteração de sintaxe.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }
Mani
fonte
Se for necessário encaminhar declarar enum (NS_ENUM): stackoverflow.com/a/42009056/342794
lal
25

A enum (abreviação de enumeração) é usada para enumerar um conjunto de valores (enumeradores). Um valor é uma 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 vai bem. Mas um dia você precisa reutilizar essa enum para definir uma nova variável para armazenar myGrandFatherPantSize, e então escreve:

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

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

Então, se você deseja 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ê usa esse conjunto, basta usar a tag. Mas não esqueça que essa tag não substitui a palavra enum, mas apenas o conjunto de enumeradores. Depois, tome cuidado para usar 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ê também pode usá-lo em uma definição de parâmetro:

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

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

Este é o passo final de nossa grande progressão para a cúpula. Apenas adicionando um typedef, vamos transformar nossa enumeração em um tipo real. Ah, a última coisa, typedef não é permitido em 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, como aqui, nesse caso, não marcamos os enumeradores, mas apenas para definir um novo tipo. Então 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ê estiver desenvolvendo no Objective-C com o XCode, deixarei descobrir algumas macros legais com o prefixo NS_ENUM. Isso deve ajudá-lo a definir boas enums facilmente e, além disso, ajudará o analisador estático a fazer algumas verificações interessantes antes de compilar.

Bom Enum!

Vincent Zgueb
fonte
Eu sempre pensei "por que alguém responderia a uma pergunta que já foi respondida e aceita"? Rapaz, eu estava errado o tempo todo! Esta é a melhor resposta e ajuda iniciantes como eu!
Rak appdev 13/03/19
10

typedefé útil para redefinir o nome de um tipo de variável existente. Ele fornece uma maneira curta e significativa de chamar um tipo de dados. por exemplo:

typedef unsigned long int TWOWORDS;

aqui, o tipo não assinado long int é redefinido para ser do tipo TWOWORDS. Portanto, agora podemos declarar variáveis ​​do tipo unsigned long int escrevendo,

TWOWORDS var1, var2;

ao invés de

unsigned long int var1, var2;
Rajneesh071
fonte
7
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;
Vivek Sehrawat
fonte
3

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

Priyanka Naik
fonte
3

Você pode usar no formato abaixo, o valor padrão bruto a partir de 0, portanto

  • kCircle é 0,
  • kRetângulo é 1,
  • kOblateSpheroid é 2.

Você pode atribuir seu próprio valor inicial específico.

typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0
Bilal Arslan
fonte
2

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

typedef int Contador; define o tipo Contador como equivalente ao tipo int. Isso melhora drasticamente a legibilidade do código.


fonte
2

O Typedef é uma palavra-chave em C e C ++. É usado para criar novos nomes para tipos de dados básicos (char, int, float, double, struct & enum) .

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Aqui ele cria o tipo de dados enumerado ShapeType e podemos escrever novos nomes para o tipo de enum ShapeType, conforme indicado abaixo

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;
Yogeesh HT
fonte
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 possui restrições. É simplesmente apenas uma substituição. Não é capaz de limitar todas as condições do estado. Quando o estado é atribuído a 5, o programa estará errado, porque não há estado correspondente. Mas o compilador não avisa STATE = 5

Então é melhor usar assim

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

SampleState state = SampleStateGood;
Marcus Thornton
fonte