多少人跪求的iOS NS_OPTIONS , 1 << 0 是個(gè)什么玩意兒?

一、這是個(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       //通知所有事件。
};

感謝文章:http://m.itdecent.cn/p/7d7163a35133

如果您有什么疑問或者書寫歧義,非常感激您能留言~

最后編輯于
?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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