1.前言
在iOS開發(fā)中旱爆,枚舉值是大家用得比較多的,但是大家一般常用的是NS_ENUM/enum,對于NS_OPTIONS大家用得可能比較少窘茁,因為NS_ENUM就能解決大部分問題怀伦,不過如果學(xué)會了NS_OPTIONS的使用,在開發(fā)中會如虎添翼山林。
2.NS_ENUM和NS_OPTIONS
既然NS_ENUM和NS_OPTIONS都是代表枚舉值房待,那么他們到底有什么區(qū)別呢?在開發(fā)中驼抹,怎么選擇使用哪一個呢桑孩?
先來簡單的說說區(qū)別:NS_ENUM通常來說,只能選擇一個值砂蔽,而NS_OPTIONS由于是位移枚舉洼怔,可以進(jìn)行計算署惯,所以NS_OPTIONS通匙蠹荩可以選擇多個值。從他們的區(qū)別可以看出來极谊,我們在開發(fā)中诡右,如果是需要使用固定的值,而且只會有一種狀態(tài)轻猖,比如網(wǎng)絡(luò)請求帆吻,要么是200,要么是400咙边,要么是500等等猜煮,不可能出現(xiàn)既是200的情況又是400的情況次员,在這種只有一個取值的情況下,選擇NS_ENUM就好了王带,而對于一個狀態(tài)可以有多個取值的淑蔚,比如如果給按鈕設(shè)置圓角,那么有上下左右4個方向愕撰,而你可以只設(shè)置左邊有圓角刹衫,也可以設(shè)置左邊和右邊有圓角,這樣就有很多種排列組合搞挣。
所以带迟,綜上來說,對于只有一種取值情況的囱桨,用NS_ENUM就可以仓犬,對于可以有多種情況的,用NS_OPTIONS最簡單蝇摸。
本文會以星期的選擇為例子婶肩,來詳細(xì)講解NS_OPTIONS,通過這個例子貌夕,大家可以知道在開發(fā)中律歼,怎么去定義,怎么使用啡专,怎么取消選中险毁,怎么拿到值了進(jìn)行選中。但是里面會涉及一些編碼们童,補(bǔ)碼畔况,反碼的知識,本文就不詳細(xì)的講解了慧库,大家感興趣的可以詳細(xì)的去查找一下資料(主要是由于年代久遠(yuǎn)跷跪,當(dāng)初學(xué)習(xí)的數(shù)字電路知識大部分忘記了,只知道怎么使用齐板,忘記原理了:((()吵瞻。
3.NS_OPTIONS的定義
//星期選擇
typedef NS_OPTIONS(NSInteger, ALWeekRepeat) {
ALWeekRepeatNone = 0,//未選擇
ALWeekRepeatMonday = 1<<1,
ALWeekRepeatTuesday = 1<<2,
ALWeekRepeatWednesday = 1<<3,
ALWeekRepeatThursday = 1<<4,
ALWeekRepeatFriday = 1<<5,
ALWeekRepeatSaturday = 1<<6,
ALWeekRepeatSunday = 1<<7
};
從定義可以看出,就是讓每一位代表一個值甘磨。簡單來說,NS_OPTIONS換算下來也是普通的值橡羞,比如第一位,換算下來定義的就是1济舆,第二位換算下來就是2卿泽,第三位是4。有人可能有疑惑滋觉,既然換算下來是這樣的值签夭,那么我定義得時候用NS_ENUM定義成1齐邦,2,3第租,4侄旬,然后進(jìn)行或運算不更簡單嗎?但你仔細(xì)算一下你會發(fā)現(xiàn)煌妈,有些兩個值組合會等于另一個單獨定義得值儡羔,你會分不清這個值到底是代表我定義得值,還是說這個值是單獨定義的值璧诵。打個比方汰蜘,假如你1 | 2 = 3,那么你就分不清楚這個得出的結(jié)果到底是我單獨定義的3呢之宿,還是兩個1|2的計算結(jié)果族操。所以用NS_OPTIONS來進(jìn)行定義,保證每一位只代表一個值比被,兩個值進(jìn)行或計算就是一個獨一無二的值色难,不會出現(xiàn)這種沖突的情況,而起因為有左移運算<<等缀,你不需要具體的去計算哪一位的值是多少枷莉,只需要進(jìn)行定義下去就行。
4.NS_OPTIONS的多個選擇與取消選擇
NSArray *weekarray = @[@"M",@"TU",@"W",@"TH",@"F",@"SA",@"SU"];
CGFloat weekButtonWidth = 30;
CGFloat margin = (self.view.frame.size.width - weekButtonWidth * 7) / 8;
for (NSInteger i = 0; i < weekarray.count; i++) {
UIButton *weekBtn = [[UIButton alloc]init];
weekBtn.tag = i;
weekBtn.frame = CGRectMake( margin + i * (margin + weekButtonWidth), 100, weekButtonWidth, weekButtonWidth);
[weekBtn setTitle:weekarray[i] forState:UIControlStateNormal];
[weekBtn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[weekBtn setTitleColor:RGB(33, 209, 102) forState:UIControlStateSelected];
weekBtn.adjustsImageWhenHighlighted = NO;
[weekBtn addTarget:self action:@selector(weekBtnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:weekBtn];
}
上圖是一個簡單的定義星期的UI尺迂。建議大家排列順序和你的定義的枚舉值進(jìn)行一一對應(yīng)笤妙,比如你第一位定義的是星期一,那么你的按鈕就從星期一開始噪裕,這樣方便后面的選擇計算蹲盘。
對于選中,這個比較簡單膳音,進(jìn)行或運算即可召衔,如果用戶取消了,由于&是與|相對的祭陷,只需要進(jìn)行&即可苍凛,但是,記得一定要取反才行(具體原理忘記了颗胡,反正就是那些反碼相關(guān)的知識)毫深。按鈕點擊的方法如下:
-(void)weekBtnClick:(UIButton *)button{
button.selected = !(button.selected);
if (button.isSelected) {
_tempWeekRepeat |= 1<<(button.tag +1);
button.backgroundColor = RGB(242, 242, 242);
button.layer.cornerRadius = 15;
button.layer.masksToBounds = YES;
}else{
_tempWeekRepeat &= ~(1<<(button.tag +1));
button.backgroundColor = [UIColor whiteColor];
button.layer.cornerRadius = 0;
}
}
_tempWeekRepeat是一個定義的全局變量吩坝,用來記錄這次用戶的點擊與取消點擊毒姨。
5.通過枚舉值設(shè)置按鈕的選中狀態(tài)
經(jīng)驗老到的后臺,基本都會知道位運算钉寝,這時候他就會要求你傳選中狀態(tài)的計算值給到他弧呐,比如選擇了星期一和星期三闸迷,那么計算出來的值是5,后臺也就只需要5俘枫,他就知道用戶選擇了星期幾腥沽。當(dāng)你去get下載下來的值,也是這個值鸠蚪,這時候今阳,要怎樣在用戶的界面顯示出來呢,其實也很簡單茅信,只需要在創(chuàng)建按鈕for循環(huán)的時候判斷一下即可盾舌。
if ((_tempWeekRepeat & (1<<(i+1)))) {
weekBtn.selected = YES;
weekBtn.backgroundColor = RGB(242, 242, 242);
}
這樣就能知道5的意思是選中了星期一和星期三。
當(dāng)然了如果你們后臺是要求傳一些奇葩的值蘸鲸,比如[0,0,0,0,1,0,1]代表星期一和星期三選中妖谴。那么你就需要自己和他溝通,叫他學(xué)習(xí)一下位移枚舉酌摇,或者是你自己解決了膝舅。
6.結(jié)語
位移枚舉NS_OPTIONS對于這種有多個狀態(tài)的情況,是相當(dāng)?shù)挠押靡ざ啵疫@里基本把開發(fā)中常用的選中與取消選中仍稀,以及服務(wù)器上的值怎么讓按鈕選中進(jìn)行了演示,如果你需要開發(fā)中使用完全沒問題埂息,但是如果你想知道具體實現(xiàn)的原理琳轿,你就需要去查詢一下相關(guān)的編碼、補(bǔ)碼耿芹、反碼的知識了崭篡。
可能本文講解的不是很詳細(xì),所以demo附上吧秕,供各位參考琉闪,你只需要用一下demo,就會知道具體的使用:https://github.com/CHNDarryl/OptionDemo
另外砸彬,代碼也不多颠毙,在附一張代碼截圖: