Objective-Cのtypedef enumとは何ですか?


1087

私はそれが何であるか、enumいつそれを使うべきかを根本的に理解しているとは思いません。

例えば:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

ここで実際に何が宣言されていますか?


2
ユーザー定義型は「列挙型」と呼ばれていますか?これは、複数のtypedef enum宣言を持つコードに出会うまで、私が考えていたものです。
クレイグ、

8
いいえ、ユーザー定義タイプはShapeTypeです。typedefについて読んでください:en.wikipedia.org/wiki/Typedef
ランピオン

6
Objective-CのtypedefはCのtypedefとまったく同じです。また、Objective-CのenumはCのenumとまったく同じです。これは、3つの定数kCircle = 0、kRectangle = 1およびkOblateSpheroid =を持つenumを宣言します2、列挙型にShapeTypeという名前を付けます。あなたは何を「のtypedef」と「列挙型」の手段がわからない場合は、C.についての本を買う
gnasher729

回答:


1565

三つのことがここで宣言されています:匿名の列挙型が宣言され、ShapeTypeその匿名の列挙のtypedefを宣言し、3人の名前されているkCirclekRectanglekOblateSpheroidの積分定数として宣言されています。

分解してみましょう。最も単純なケースでは、列挙は次のように宣言できます。

enum tagname { ... };

これは、タグで列挙を宣言しますtagname。CおよびObjective-C(C ++ではない)では、これへの参照の前にキーワードを付ける必要ありますenum。例えば:

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

enumどこでもキーワードを使用する必要がないように、typedefを作成できます。

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

これは1行に簡略化できます。

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

私たちが使用できるようにする必要がない場合そして最後に、enum tagnameenumキーワード、我々は作ることができenum、匿名をし、唯一のtypedef名でそれを宣言します。

typedef enum { ... } tagname;

さて、このケースでShapeTypeは、匿名の列挙のtypedefされた名前であることを宣言しています。 ShapeType実際には整数型であり、そして唯一の(である、のいずれかの宣言に列挙された値のいずれかを保持する変数を宣言するために使用されるべきであるkCirclekRectangleなどをkOblateSpheroid)。ShapeTypeただし、キャストによって変数に別の値を割り当てることができるため、列挙値を読み取るときは注意する必要があります。

最後に、kCirclekRectangle、およびkOblateSpheroidグローバル名前空間での積分定数として宣言されています。具体的な値が指定されていなかったので、彼らは、0から始まる連続した整数に割り当てられますので、kCircle0であり、kRectangle1、kOblateSpheroid2です。


6
いい説明-一つだけ付け加えると、構造体はCでの同様の命名規則に従います(Objective-Cについてはわかりません)。
マイケル・バー、

109
Objective-CはCの適切なスーパーセットです。CのすべてのC構造体命名規則は、Objective-Cでも同様に有効です。
sigjuice

驚くばかり。C ++スタイルの列挙型だけを使用できます。列挙型を記述する必要もありません:)
user4951

11
宣言するファイルが.mではなく.mmファイルである場合は、C ++スタイルの列挙を使用できます。Objective-C ++はとてつもなく強力です。
Kevin Hoffman

14
そして、この答えを理解したら、新しいNS_ENUMとNS_OPTIONSを見てみる価値があります。ここではチュートリアル:nshipster.com/ns_enum-ns_options SOここと:stackoverflow.com/questions/14080750/...
Snowcrash

254

Xcode 4.4以降では、このような列挙型を定義することをお勧めします。

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

また、便利なマクロも提供しますNS_ENUM

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

これらの定義により、型チェックが強化され、コード補完が改善されます。の公式ドキュメントは見つかりませんでしたがNS_ENUM、WWDC 2012セッションの「Modern Objective-C」ビデオはこちらでご覧いただけます


UPDATE
公式ドキュメントへのリンクはこちら


13
5時58分に「列挙型の改善」開始について一部
vikingosegundo

5
別の回答についてコメントしたようにNS_ENUM、NSHipsterによるAppleのマクロの説明を参照してください:NSHipster.com/ns_enum-ns_options
Basil Bourque

1
これはNS_ENUMに関する公式ドキュメントへのリンクです:developer.apple.com/library/ios/releasenotes/ObjectiveC/...
YoGiN

50

enumは一連の順序付けされた値を宣言します-typedefはこれに便利な名前を追加するだけです。最初の要素は0などです。

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

WORKDAYS today = Monday;

上記は、shapeTypeタグの列挙にすぎません。


34

の可能な値を持つユーザー定義型kCirclekRectangleまたはkOblateSpheroid。ただし、列挙型の内部の値(kCircleなど)は列挙型の外側に表示されます。それを覚えておくことが重要int i = kCircle;です(たとえば、有効です)。


30

64ビットの変更に対する更新:64ビットの変更に関するアップルのドキュメントに よると、

列挙型も型付けされます:LLVMコンパイラでは、列挙型は列挙型のサイズを定義できます。これは、一部の列挙型のサイズが予想よりも大きい場合があることを意味します。他のすべての場合と同様に、解決策は、データ型のサイズについて仮定を行わないことです。代わりに、列挙値を適切なデータ型の変数に割り当てます

したがって、64ビットをサポートする場合は、次の構文のような型の列挙型作成する必要があります。

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

または

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

それ以外の場合は、次のように警告が表示されます Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

迅速なプログラミングのための更新:

迅速に、構文の変更があります。

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

もし、前方宣言列挙型(NS_ENUM)する必要があります。stackoverflow.com/a/42009056/342794
LAL

25

enum(列挙の省略形)は、一連の値(列挙子)を列挙するために使用されます。値は、記号(単語)で表される抽象的なものです。たとえば、基本的な列挙型は

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

この列挙型は、名前を付けるシンボルがないため、匿名と呼ばれます。しかし、それはまだ完全に正しいです。このように使うだけ

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

OK。人生は美しく、すべてがうまくいきます。しかし、ある日、この列挙型を再利用して、myGrandFatherPantSizeを格納する新しい変数を定義する必要がある場合は、次のように記述します。

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

しかし、「列挙子の再定義」というコンパイラエラーが発生します。実際、問題は、コンパイラが最初に列挙型であり、2番目に同じものを記述していることを確信していないことです。

次に、同じセットの列挙子(ここではxs ... xxxxl)を複数の場所で再利用する場合は、一意の名前でタグ付けする必要があります。このセットを2回目に使用するときは、タグを使用する必要があります。ただし、このタグは列挙型の単語を置き換えるのではなく、列挙子のセットを置き換えるだけであることを忘れないでください。次に、いつものように列挙型を使用するように注意してください。このような:

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

パラメータ定義でも使用できます。

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

enumをどこでも書き直すのは便利ではなく、コードが少し奇妙に見えると言うことができます。あなたが正しいです。実際のタイプの方が良いでしょう。

これは、サミットへの大きな前進の最後のステップです。typedefを追加するだけで、列挙型を実際の型に変換できます。最後に、typedefはクラス内では許可されていません。次に、上のタイプを定義します。次のようにします。

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

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

タグはオプションです。次に、ここから、その場合、列挙子にタグを付けるのではなく、新しいタイプを定義するだけにします。そうすれば、もう必要ありません。

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

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

XCodeを使用してObjective-Cで開発している場合は、NS_ENUMで始まるいくつかの素晴らしいマクロを発見できます。これは、適切な列挙型を簡単に定義するのに役立ち、さらに、静的アナライザーがコンパイルする前に興味深いチェックを行うのに役立ちます。

良い列挙!


私はいつも「すでに答えられて受け入れられている質問に誰が答えるのか」と常に考えていました。少年、私はいつも間違っていました!これが最良の答えであり、私のような初心者を助けます!
rak appdev 2017年

10

typedef既存の変数タイプの名前を再定義するのに役立ちます。これは、データ型を呼び出すための短くて意味のある方法を提供します。例えば:

typedef unsigned long int TWOWORDS;

ここでは、unsigned long int型がTWOWORDS型に再定義されています。したがって、次のように記述することで、unsigned long int型の変数を宣言できます。

TWOWORDS var1, var2;

の代わりに

unsigned long int var1, var2;

7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

それからあなたはそれを次のように使うことができます:-

 ShapeType shape;

そして

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

今、あなたはそれを次のように使うことができます:-

enum ShapeType shape;

3

enumは、構造体では実行できないenum要素に値を割り当てるために使用されます。したがって、毎回、完全な変数にアクセスする代わりに、列挙型の変数に割り当てる値でアクセスできます。デフォルトでは、0の割り当てから始まりますが、任意の値を割り当てることができます。列挙型の次の変数には、前の値+1の値が割り当てられます。


3

以下のフォーマットで使用できます。0から始まるRawデフォルト値なので、

  • kCircleは0、
  • kRectangleは1です
  • kOblateSpheroidは2です。

独自の開始値を割り当てることができます。

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

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

2

typedefを使用すると、プログラマはObjective-Cの型を別の型として定義できます。例えば、

typedef int Counter; Counterタイプをintタイプと同等に定義します。これにより、コードの可読性が大幅に向上します。


2

Typedefは、CおよびC ++のキーワードです。これは、基本データ型(char、int、float、double、struct&enum)の新しい名前を作成するために使用されます。

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

ここでは、列挙型データ型ShapeTypeが作成されます。次に示すように、列挙型ShapeTypeの新しい名前を書き込むことができます。

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

1

enumは多くのタイプの「エラー」を減らし、コードをより管理しやすくします

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

定義に制約はありません。それは単に代替品です。状態のすべての条件を制限することはできません。STATEが5に割り当てられている場合、一致する状態がないため、プログラムは正しくありません。しかし、コンパイラーはSTATE = 5に警告しません

だからこのように使う方がいい

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

SampleState state = SampleStateGood;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.