一、這是個(gè)什么東西?
- NS_OPTIONS :這就是個(gè)枚舉。
- 1 << 0 : 位運(yùn)算,這個(gè)結(jié)果其實(shí)就是十進(jìn)制的1
| 位運(yùn)算 | 十進(jìn)制值 |
|---|---|
| 1 << 0 | 1 |
| 1 << 1 | 2 |
| 1 << 2 | 4 |
| 1 << 3 | 8 |
| 1 << 4 | 16 |
| 1 << 5 | 32 |
| Sample << N | Sample乘以2的N次方 |
結(jié)果就是將Sample的二進(jìn)制數(shù)向左移動(dòng)N位,即Sample乘以2的N次方。N為非負(fù)整數(shù)
二、這玩意兒有什么用
拿我們常用的UIControlEvents來舉例子(附錄有枚舉詳細(xì)中文注釋)
- 定義識(shí)別方法
就是用來識(shí)別傳入了些什么值,如果傳入了UIControlEventTouchDown就輸出對(duì)應(yīng)的字符串。(先粗看瀏覽,看完原理后再回頭看這個(gè))
- (void)recognizeOrientation:(UIControlEvents)controlEventType{
if (controlEventType & UIControlEventTouchDown) {
NSLog(@"UIControlEventTouchDown");
}
if (controlEventType & UIControlEventTouchDownRepeat) {
NSLog(@"UIControlEventTouchDownRepeat");
}
if (controlEventType & UIControlEventTouchDragInside) {
NSLog(@"UIControlEventTouchDragInside");
}
if (controlEventType & UIControlEventTouchDragOutside) {
NSLog(@"UIControlEventTouchDragOutside");
}
if (controlEventType & UIControlEventTouchDragEnter) {
NSLog(@"UIControlEventTouchDragEnter");
}
if (controlEventType & UIControlEventTouchDragExit) {
NSLog(@"UIControlEventTouchDragExit");
}
if (controlEventType & UIControlEventTouchUpInside) {
NSLog(@"UIControlEventTouchUpInside");
}
if (controlEventType & UIControlEventTouchCancel) {
NSLog(@"UIControlEventTouchCancel");
}
if (controlEventType & UIControlEventValueChanged) {
NSLog(@"UIControlEventValueChanged");
}
if (controlEventType & UIControlEventPrimaryActionTriggered) {
NSLog(@"UIControlEventPrimaryActionTriggered");
}
if (controlEventType & UIControlEventEditingDidBegin) {
NSLog(@"UIControlEventEditingDidBegin");
}
if (controlEventType & UIControlEventEditingChanged) {
NSLog(@"UIControlEventEditingChanged");
}
if (controlEventType & UIControlEventEditingDidEnd) {
NSLog(@"UIControlEventEditingDidEnd");
}
if (controlEventType & UIControlEventEditingDidEndOnExit) {
NSLog(@"UIControlEventEditingDidEndOnExit");
}
}
- 使用
- (void)viewDidLoad {
[super viewDidLoad];
UIControlEvents controlEvent = UIControlEventTouchDown | UIControlEventTouchUpInside | UIControlEventValueChanged | UIControlEventEditingDidBegin | UIControlEventEditingDidEndOnExit;
[self recognizeOrientation:controlEvent];
}
-
打印結(jié)果
打印結(jié)果.png
哇好神奇,傳入幾個(gè),就可以打印幾個(gè)出來。
看到好用的地方?jīng)],這種定義枚舉的優(yōu)點(diǎn)在于,當(dāng)某個(gè)枚舉變量的值取其中某幾個(gè)時(shí)(即包含多種可能,通過 | 來賦值)。
要判斷是否包含其中某一種可能(該種可能對(duì)應(yīng)的枚舉二進(jìn)制值必然有且只有一位為0),只要將變量同該枚舉值按位求與結(jié)果大于0則說明包含。
類似的在SDWebImage中也有
//傳入多種模式
[btn sd_setBackgroundImageWithURL:url
forState:UIControlStateNormal
options:SDWebImageLowPriority |
SDWebImageCacheMemoryOnly |
SDWebImageProgressiveDownload];
三、和NS_ENUM 、enum 有什么不同
- 如果需要以按位或操作來組合的枚舉都應(yīng)該使用NS_OPTIONS宏;
- 若枚舉不需要互相組合,可以使用NS_ENUM來定義
- NS_ENUM和NS_OPTIONS本質(zhì)是一樣的,僅僅從字面上來區(qū)分其用途,采用不同的宏來從代碼角度來區(qū)分
- enum C語言的枚舉,OC也同樣適用
四、原理
我們知道,程序中的所有數(shù)在計(jì)算機(jī)內(nèi)存中都是以二進(jìn)制的形式儲(chǔ)存的。位運(yùn)算說穿了,就是直接對(duì)整數(shù)在內(nèi)存中的二進(jìn)制位進(jìn)行操作。
- 首先上面viewDidLoad 中計(jì)算出來的值為:
UIControlEvents controlEvent = UIControlEventTouchDown | UIControlEventTouchUpInside | UIControlEventValueChanged | UIControlEventEditingDidBegin | UIControlEventEditingDidEndOnExit;
controlEvent = 1 << 0| 1 << 6|1 << 12|1 << 16|1 << 19;
controlEvent = 1 | 64 | 4096 | 65536 | 524288;
controlEvent = 593985;
- 其次在方法里邊計(jì)算出來的值為:
//傳入了UIControlEventTouchUpInside 計(jì)算結(jié)果大于0 所以輸出
if (controlEventType & UIControlEventTouchUpInside) {
/*
593985 & 64 (10進(jìn)制)
10010001000001000001 & 1000000 (2進(jìn)制)
= 1000000 (2進(jìn)制)
= 64 大于0為真 (10進(jìn)制)
*/
NSLog(@"UIControlEventTouchDown");
}
//未傳入U(xiǎn)IControlEventTouchDragExit 計(jì)算結(jié)果等于0 所以沒有輸出
if (controlEventType & UIControlEventTouchDragExit) {
/*
593985 & 32 (10進(jìn)制)
10010001000001000001 & 100000 (2進(jìn)制)
= 0 (2進(jìn)制)
= 0 等于0為假 (10進(jìn)制)
*/
NSLog(@"UIControlEventTouchDragExit");
}
通過這樣就達(dá)到了傳入多個(gè)enum值。不得不佩服~
五、延伸
當(dāng)按照上面viewDidLoad那樣傳值,在進(jìn)行按位與&進(jìn)行計(jì)算 controlEventType & UIControlEventAllEvents = 593985,是大于0的。也就 意味著字符串@"UIControlEventAllEvents" 會(huì)輸出,即你隨便傳入一個(gè)事件,系統(tǒng)就會(huì)認(rèn)為這是個(gè)觸摸事件,在邏輯上也合理。也就體現(xiàn)出蘋果系統(tǒng)在觸摸事件上的包含性了。
附錄
typedef NS_OPTIONS(NSUInteger, UIControlEvents) {
UIControlEventTouchDown = 1 << 0, // 單點(diǎn)觸摸按下事件:用戶點(diǎn)觸屏幕,或者又有新手指落下的時(shí)候。
UIControlEventTouchDownRepeat = 1 << 1, // 多點(diǎn)觸摸按下事件,點(diǎn)觸計(jì)數(shù)大于1:用戶按下第二、三、或第四根手指的時(shí)候。
UIControlEventTouchDragInside = 1 << 2, //當(dāng)一次觸摸在控件窗口內(nèi)拖動(dòng)時(shí)
UIControlEventTouchDragOutside = 1 << 3, //當(dāng)一次觸摸在控件窗口之外拖動(dòng)時(shí)。
UIControlEventTouchDragEnter = 1 << 4, //當(dāng)一次觸摸從控件窗口之外拖動(dòng)到內(nèi)部時(shí)。
UIControlEventTouchDragExit = 1 << 5, //當(dāng)一次觸摸從控件窗口內(nèi)部拖動(dòng)到外部時(shí)。
UIControlEventTouchUpInside = 1 << 6, //所有在控件之內(nèi)觸摸抬起事件。
UIControlEventTouchUpOutside = 1 << 7, //所有在控件之外觸摸抬起事件(點(diǎn)觸必須開始與控件內(nèi)部才會(huì)發(fā)送通知)
UIControlEventTouchCancel = 1 << 8, //所有觸摸取消事件,即一次觸摸因?yàn)榉派狭颂嗍种付蝗∠?,或者被上鎖或者電話呼叫打斷。
UIControlEventValueChanged = 1 << 12, //當(dāng)控件的值發(fā)生改變時(shí),發(fā)送通知。用于滑塊、分段控件、以及其他取值的控件。你可以配置滑塊控件何時(shí)發(fā)送通知,在滑塊被放下時(shí)發(fā)送,或者在被拖動(dòng)時(shí)發(fā)送
UIControlEventPrimaryActionTriggered = 1 << 13, //當(dāng)控件的首要行為被觸發(fā),例如button的點(diǎn)擊事件,slider的滑動(dòng)事件。iOS_9之后可用
UIControlEventEditingDidBegin = 1 << 16, //當(dāng)文本控件中開始編輯時(shí)發(fā)送通知。
UIControlEventEditingChanged = 1 << 17, //當(dāng)文本控件中的文本被改變時(shí)發(fā)送通知。
UIControlEventEditingDidEnd = 1 << 18, //當(dāng)文本控件中編輯結(jié)束時(shí)發(fā)送通知
UIControlEventEditingDidEndOnExit = 1 << 19, // 當(dāng)文本控件內(nèi)通過按下回車鍵(或等價(jià)行為)結(jié)束編輯時(shí),發(fā)送通知。
UIControlEventAllTouchEvents = 0x00000FFF, //通知所有觸摸事件。
UIControlEventAllEditingEvents = 0x000F0000, //通知所有關(guān)于文本編輯的事件。
UIControlEventApplicationReserved = 0x0F000000, // 為應(yīng)用程序預(yù)留
UIControlEventSystemReserved = 0xF0000000, //為系統(tǒng)內(nèi)部框架預(yù)留
UIControlEventAllEvents = 0xFFFFFFFF //通知所有事件。
};
