對于OC中的枚舉類型,雖然知道有NS_ENUM和NS_OPTION,然而并不是十分清楚它們之間的區(qū)別肮韧。另外,也很好奇旺订,OC中為什么幾乎不使用enum弄企,以及這三種枚舉類型之間的差異。
通過查閱資料区拳,同時編寫代碼調(diào)試拘领,總算弄清楚了之前的問題,所以寫這篇文章來進(jìn)行總結(jié)樱调。
enum的局限性
在枚舉的聲明中约素,使用typedef可以使得枚舉變量的聲明更簡單。
typedef enum {
FlyStateOne,
FlyStateTwo,
FlyStateThree
}FlyState;
enum FlyTypeState{
FlyTypeOne,
FlyTypeTwo,
FlyTypeThree
};
FlyState state笆凌;
typedef enum FlyTypeState state;
C++11標(biāo)準(zhǔn)擴(kuò)充了枚舉的類型圣猎,通過新式枚舉,可以指明枚舉的底層數(shù)據(jù)類型乞而。這樣送悔,就可以確定給枚舉變量分配多少空間,從而能夠向前聲明枚舉變量。
而對于enum來說欠啤,不能直接在使用typedef的同時荚藻,確定枚舉的底層數(shù)據(jù)類型。
typedef enum {
FlyStateOne,
FlyStateTwo,
FlyStateThree
}FlyState;
enum FlyState:NSInteger{ //設(shè)置底層數(shù)據(jù)類型為NSInteger
FlyStateOne,
FlyStateTwo,
FlyStateThree
};
上面的兩種聲明方式洁段,都是正確的应狱,而下面的這種聲明方式是錯的:
typedef enum FlyState1:NSInteger{
FlyStateOne1,
FlyStateTwo1,
FlyStateThree1
};
enum如果想在使用typedef的同時,確定底層數(shù)據(jù)類型眉撵,就只能使用兩條語句:
typedef enum FlyState:NSInteger FlyState;
enum FlyState : NSInteger {
FlyStateOne,
FlyStateTwo,
FlyStateThree
};
這樣侦香,很顯然在寫代碼的時候比較麻煩落塑。
NS_ENUM和enum的不同
NS_ENUM是一個OC中的宏纽疟,可以判斷編譯器能否采用新式枚舉:如果不能,那么效果等同于僅僅使用typedef的enum憾赁;如果能夠采用新式枚舉污朽,那么NS_ENUM所定義的枚舉類型,就是處理后的enum類型龙考,可以在使用typedef的同時蟆肆,指定底層數(shù)據(jù)類型。
比如:
typedef NS_ENUM(NSInteger, FlyState) {
FlyStateOne,
FlyStateTwo,
FlyStateThree
};
如果支持新式枚舉晦款,展開之后炎功,就是:
typedef enum FlyState:NSInteger FlyState;
enum FlyState : NSInteger {
FlyStateOne,
FlyStateTwo,
FlyStateThree
};
此時,既指定了數(shù)據(jù)類型缓溅,又可以使用:
FlyState state = FlyStateOne蛇损;
很明顯,NS_ENUM就是對enum的一種封裝坛怪。所以淤齐,在OC中,幾乎不使用enum袜匿,都是使用NS_ENUM和NS_OPTION更啄。
按位或 枚舉的作用
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
};
需要同時滿足多個枚舉條件時,使用按位或操作來進(jìn)行組合居灯。 比如:
UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleTopMargin
用于表示同時限制右邊距和頭部邊距
NS_ENUM和NS_OPTIONS的不同
NS_OPTIONS也是OC中的一個宏祭务。
在用或運算處理兩個枚舉類型時,C++ 認(rèn)為枚舉結(jié)果的數(shù)據(jù)類型應(yīng)該是枚舉的底層數(shù)據(jù)類型(即NSUInteger)怪嫌,而且C++不允許將這個底層類型隱式轉(zhuǎn)換成枚舉類型本身待牵。
比如:
typedef NS_ENUM(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
此時:
UIViewAutoresizing viewModel =UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight
得到的枚舉結(jié)果的類型是NSUInteger,而不是UIViewAutoresizing喇勋。編譯器會報錯缨该。
針對這種情況,NS_OPTIONS做了處理川背,區(qū)分了C++ 模式編譯和非C++ 模式編譯贰拿。在非C++ 編譯模式下蛤袒,NS_OPTIONS和NS_ENUM是一樣的。對于C++模式編譯膨更,NS_OPTIONS會做一些特殊處理妙真,保證枚舉結(jié)果的類型正確。
總結(jié)
NS_ENUM的作用是在使用typedef的同時荚守,確定枚舉的底層數(shù)據(jù)類型珍德,這個效果是enum所達(dá)不到的。NS_OPTIONS的作用是矗漾,在NS_ENUM的基礎(chǔ)上锈候,使得按位或運算的結(jié)果能夠返回正確的數(shù)據(jù)類型。
所以敞贡,凡是需要以按位或操作來進(jìn)行組合的枚舉都需要用NS_OPTIONS定義泵琳,若不需要組合,則可以使用NS_ENUM誊役。
文中如有錯誤获列,歡迎指正。