[iOS-Objective-C] 枚舉

參考資料

《編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法》中第5條:用枚舉表示狀態(tài)、選項(xiàng)、狀態(tài)碼

枚舉類型的基本使用

枚舉的作用在于規(guī)范并語義化的定義代碼中的狀態(tài)、選項(xiàng)等常量。枚舉類型的定義以關(guān)鍵字enum開頭,之后是枚舉數(shù)據(jù)類型的名稱,最后是在一對(duì)花括號(hào)內(nèi)的選項(xiàng)標(biāo)識(shí)符序列。 編譯器會(huì)為枚舉分配一個(gè)獨(dú)有的編號(hào),從0開始,每個(gè)枚舉遞增1。

enum  Direction {up, down, left, right};

實(shí)現(xiàn)枚舉所用的數(shù)據(jù)類型取決于編譯器。除了使用默認(rèn)類型,還可以指明用何種“底層數(shù)據(jù)類型”來保存枚舉類型的變量。

enum Direction : UNSInteger {up, down, left, right};

還可以不使用編譯器所分配的序號(hào),而是手工指定某個(gè)枚舉成員所對(duì)應(yīng)的值。如下例中將 up 的值設(shè)為1,而不使用編譯器所分配的0。接下來的枚舉值會(huì)在上一個(gè)的基礎(chǔ)上遞增1。

enum Direction {up = 1, down, left, right};

枚舉的另一種使用方式是定義為按位掩碼,當(dāng)定義選項(xiàng)的時(shí)候,若這些選項(xiàng)可以彼此組合,則在設(shè)置特定的枚舉值后,各選項(xiàng)間就可通過“按位或”來組合。因?yàn)槊總€(gè)枚舉值所對(duì)應(yīng)的二進(jìn)制表示中,只有1個(gè)二進(jìn)制位的值是1,所以多個(gè)選項(xiàng)“按位或”后的組合值是唯一的,且將某一選項(xiàng)與組合值做“按位與”操作,即可判斷出組合值中是否包含該選項(xiàng)。

enum Direction {
   up = 1 << 0, 
   down = 1 << 1, 
   left = 1 << 2, 
   right = 1 << 3
};

使用關(guān)鍵字 typedef 重新定義枚舉

然而聲明或定義一個(gè)枚舉類型變量的方式卻不太簡潔,仍然需要使用enum關(guān)鍵字,如:

enum  Direction {up, down, left, right};
enum Direction var1;

enum {up, down, left, right} var1;

為了簡化枚舉的聲明,不需要每次都寫enum,可以使用關(guān)鍵字typedef重新定義枚舉類型

enum {up, down, left, right} Direction;
typedef enum Direction Direction;

之后就可以直接用 Direction 來代替完整的 enum Direction 了:

Direction var1, var2;

使用枚舉的正確姿勢(shì)

蘋果對(duì) Objective-C 語言支持了兩個(gè)有關(guān)枚舉的輔助弘,分別是NS_ENUMNS_OPTIONS。NS_ENUM用來定義普通的枚舉類型,NS_OPTIONS用來定義可組合選項(xiàng)的枚舉類型。

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

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

這些宏是用#define預(yù)處理指令來定義的,具備向后兼容能力,如果目標(biāo)平臺(tái)的編譯器支持新標(biāo)準(zhǔn),那就使用新式語法,否則改用舊式語法。具體的定義如下:

#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
  #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
  #if (__cplusplus)
    #define NS_OPTIONS(_type, _name) _type _name; enum : _type
  #else
    #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
  #endif
#else
  #define NS_ENUM(_type, _name) _type _name; enum
  #define NS_OPTIONS(_type, _name) _type _name; enum
#endif

上述代碼首先判斷編譯器是否支持新式枚舉,如果不支持,那么NS_ENUMNS_OPTIONS都使用相同的老式語法來定義枚舉:

typedef NSInteger Direction;
enum {up, down, left, right};

但是,舊式的語法無法告訴編譯器重新定義的枚舉類型與之后 enum 定義的整形值之間的聯(lián)系。如果支持新特性,那么NS_ENUM宏所定義的枚舉類型展開之后就是:

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

根據(jù)是否要將代碼按 C++ 編譯,NS_OPTIONS宏的定義方式也有所不同。如果不按 C++ 編譯,那么其展開方式就和NS_ENUM相同。若按 C++ 編譯,則展開后的代碼略有不同。原因在于,用按位或運(yùn)算來操作兩個(gè)枚舉值時(shí), C++ 編譯模式的處理與非 C++ 模式不一樣。在用或運(yùn)算操作兩個(gè)枚舉值時(shí), C++ 認(rèn)為運(yùn)算結(jié)果的數(shù)據(jù)類型應(yīng)該是枚舉的底層數(shù)據(jù)類型,而 C++ 不允許將這個(gè)底層類型“隱式轉(zhuǎn)換”為枚舉類型本身。如果想編譯通過,就要將按位或操作的結(jié)果“顯式轉(zhuǎn)換”為枚舉類型。所以,在 C++ 模式下應(yīng)該用另一種方式定義NS_OPTIONS宏,以便省去類型轉(zhuǎn)換操作。

鑒于此,凡是需要以按位或操作來組合的枚舉都應(yīng)使用NS_OPTIONS定義。若是枚舉不需要互相組合,則應(yīng)使用NS_ENUM來定義。

枚舉在 switch 語句中的應(yīng)用

當(dāng)在 switch 語句中使用 enum 值時(shí),不建議添加 default 分支。因?yàn)?enum 的選項(xiàng)分支已經(jīng)包含了所有可能的情況,并不需要額外處理默認(rèn)情況。而且,當(dāng)之后添加新的狀態(tài)時(shí),編譯器還會(huì)發(fā)出警告信息,提示新加入的狀態(tài)并未在 switch 分支中處理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容