web-dev-qa-db-ja.com

Objective-C列挙型、NS_ENUM&NS_OPTIONS

Objective-Cで特定のタイプの列挙型を作成する正しい方法は何ですか? NS_ENUMとNS_OPTIONSはどのように機能しますか? NS_OPTIONSは、NSAutoresizingのようなマスクに使用されますか?ありがとう。

Code from NSObjCRuntime.h
    #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
    #define NS_OPTIONS(_type, _name) _type _name; enum : _type
21
Lluís

NSHipster の例。 NS_OPTIONSも同様の方法で使用されますが、通常はビットマスクとなる列挙型に使用されます

の代わりに

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
} UITableViewCellStyle;

または

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

typedef NSInteger UITableViewCellStyle;

これを行う:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

nS_OPTIONS列挙型の例:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
34
wattson12

異なる種類の列挙を推測することを除いて、2つの間に違いがあります。

Objective-C++モードでコンパイルすると、異なるコードが生成されます。

これは元のコードです:

typedef NS_OPTIONS(NSUInteger, MyOptionType) {
    MyOptionType1 = 1 << 0,
    MyOptionType2 = 1 << 1,
};

typedef NS_ENUM(NSUInteger, MyEnumType) {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};

これは、マクロがObjective-Cコンパイルで展開されるときのコードです。

typedef enum MyOptionType : NSUInteger MyOptionType; enum MyOptionType : NSUInteger {
    MyOptionType1 = 1 << 0,
    MyOptionType2 = 1 << 1,
};

typedef enum MyEnumType : NSUInteger MyEnumType; enum MyEnumType : NSUInteger {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};

これは、マクロがObjective-C++コンパイルで展開されるときのコードです。

typedef NSUInteger MyOptionType; enum : NSUInteger {
    MyOptionType1 = 1 << 0,
    MyOptionType2 = 1 << 1,
};

typedef enum MyEnumType : NSUInteger MyEnumType; enum MyEnumType : NSUInteger {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};

2つのモード間のNS_OPTIONSの違いがわかりますか?

HERE IS THE REASON

C++ 11には新機能があり、列挙型を宣言できます。その前に、列挙型を保持する型は、列挙型の最大値に従ってコンパイラーによって決定されます。

したがって、C++ 11では、列挙型のサイズを自分で決定できるため、次のように、実際に列挙型を定義せずに、列挙型を前方宣言できます。

//forward declare MyEnumType
enum MyEnumType: NSInteger

//use myEnumType
enum MyEnumType aVar;

//actually define MyEnumType somewhere else
enum MyEnumType: NSInteger {
    MyEnumType1 = 1 << 1,
    MyEnumType2 = 1 << 2,
}

この機能は便利で、Objective-Cはこの機能をインポートしますが、次のようにビット単位の計算を行うと問題が発生します。

enum MyEnumType aVar = MyEnumType1 | MyEnumType2;

このコードはC++/Objective-C++コンパイルでコンパイルできません。これは、aVarがタイプNSIntegerと見なされているが、MyEnumType1 | MyEnumType2がタイプMyEnumTypeであるため、この割り当ては、型キャスト、C++は暗黙的な型キャストを禁止しています

現時点では、NS_OPTIONSが必要です。NS_OPTIONSはC++ 11の前に列挙型にフォールバックするため、実際にはMyEnumTypeはありません。つまり、MyEnumTypeNSIntegerの単なる別名です。次のようなコード

enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 

NSIntegerNSIntegerに割り当てているため、コンパイルされます。

8
CarmeloS