多少人跪求的iOS NS_OPTIONS , 1 << 0 是个什么玩意儿?

一、这是个什么东西?

  • NS_OPTIONS :这就是个枚举。
  • 1 << 0 : 位运算,这个结果其实就是十进制的1
位运算 十进制值
1 << 0 1
1 << 1 2
1 << 2 4
1 << 3 8
1 << 4 16
1 << 5 32
Sample << N Sample乘以2的N次方

结果就是将Sample的二进制数向左移动N位,即Sample乘以2的N次方。N为非负整数

二、这玩意儿有什么用

拿我们常用的UIControlEvents来举例子(附录有枚举详细中文注释)

  • 定义识别方法
    就是用来识别传入了些什么值,如果传入了UIControlEventTouchDown就输出对应的字符串。(先粗看浏览,看完原理后再回头看这个)
- (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]; 
}
  • 打印结果


    打印结果.png
哇好神奇,传入几个,就可以打印几个出来。

看到好用的地方没,这种定义枚举的优点在于,当某个枚举变量的值取其中某几个时(即包含多种可能,通过 | 来赋值)。
要判断是否包含其中某一种可能(该种可能对应的枚举二进制值必然有且只有一位为0),只要将变量同该枚举值按位求与结果大于0则说明包含。

类似的在SDWebImage中也有

//传入多种模式
[btn sd_setBackgroundImageWithURL:url 
                         forState:UIControlStateNormal      
                          options:SDWebImageLowPriority | 
                                  SDWebImageCacheMemoryOnly | 
                                  SDWebImageProgressiveDownload];

三、和NS_ENUM 、enum 有什么不同

  • 如果需要以按位或操作来组合的枚举都应该使用NS_OPTIONS宏;
  • 若枚举不需要互相组合,可以使用NS_ENUM来定义
  • NS_ENUM和NS_OPTIONS本质是一样的,仅仅从字面上来区分其用途,采用不同的宏来从代码角度来区分
  • enum C语言的枚举,OC也同样适用

四、原理

我们知道,程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。

  • 首先上面viewDidLoad 中计算出来的值为:
  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;
    
  • 其次在方法里边计算出来的值为:
//传入了UIControlEventTouchUpInside 计算结果大于0 所以输出
if (controlEventType & UIControlEventTouchUpInside) {
       /*
             593985           &     64              (10进制)
       10010001000001000001   &    1000000          (2进制)
       =   1000000                                  (2进制)
       =     64 大于0为真                            (10进制)
        */
        NSLog(@"UIControlEventTouchDown");
    }
//未传入UIControlEventTouchDragExit 计算结果等于0 所以没有输出
if (controlEventType & UIControlEventTouchDragExit) {
       /*
             593985           &     32             (10进制)
       10010001000001000001   &    100000          (2进制)
       =   0                                       (2进制)
       =      0 等于0为假                           (10进制)
        */
        NSLog(@"UIControlEventTouchDragExit");
    }

通过这样就达到了传入多个enum值。不得不佩服~

五、延伸

当按照上面viewDidLoad那样传值,在进行按位与&进行计算 controlEventType & UIControlEventAllEvents = 593985,是大于0的。也就 意味着字符串@"UIControlEventAllEvents" 会输出,即你随便传入一个事件,系统就会认为这是个触摸事件,在逻辑上也合理。也就体现出苹果系统在触摸事件上的包含性了。

附录

typedef NS_OPTIONS(NSUInteger, UIControlEvents) {
    UIControlEventTouchDown                = 1 <<  0,      // 单点触摸按下事件:用户点触屏幕,或者又有新手指落下的时候。
    UIControlEventTouchDownRepeat          = 1 <<  1,      // 多点触摸按下事件,点触计数大于1:用户按下第二、三、或第四根手指的时候。
    UIControlEventTouchDragInside          = 1 <<  2,      //当一次触摸在控件窗口内拖动时
    UIControlEventTouchDragOutside         = 1 <<  3,      //当一次触摸在控件窗口之外拖动时。
    UIControlEventTouchDragEnter           = 1 <<  4,      //当一次触摸从控件窗口之外拖动到内部时。
    UIControlEventTouchDragExit            = 1 <<  5,      //当一次触摸从控件窗口内部拖动到外部时。
    UIControlEventTouchUpInside            = 1 <<  6,      //所有在控件之内触摸抬起事件。
    UIControlEventTouchUpOutside           = 1 <<  7,      //所有在控件之外触摸抬起事件(点触必须开始与控件内部才会发送通知)
    UIControlEventTouchCancel              = 1 <<  8,      //所有触摸取消事件,即一次触摸因为放上了太多手指而被取消,或者被上锁或者电话呼叫打断。
    UIControlEventValueChanged             = 1 << 12,      //当控件的值发生改变时,发送通知。用于滑块、分段控件、以及其他取值的控件。你可以配置滑块控件何时发送通知,在滑块被放下时发送,或者在被拖动时发送
    UIControlEventPrimaryActionTriggered   = 1 << 13,      //当控件的首要行为被触发,例如button的点击事件,slider的滑动事件。iOS_9之后可用
    UIControlEventEditingDidBegin          = 1 << 16,      //当文本控件中开始编辑时发送通知。
    UIControlEventEditingChanged           = 1 << 17,      //当文本控件中的文本被改变时发送通知。
    UIControlEventEditingDidEnd            = 1 << 18,      //当文本控件中编辑结束时发送通知
    UIControlEventEditingDidEndOnExit      = 1 << 19,      // 当文本控件内通过按下回车键(或等价行为)结束编辑时,发送通知。
    UIControlEventAllTouchEvents           = 0x00000FFF,      //通知所有触摸事件。
    UIControlEventAllEditingEvents         = 0x000F0000,      //通知所有关于文本编辑的事件。
    UIControlEventApplicationReserved      = 0x0F000000,      // 为应用程序预留
    UIControlEventSystemReserved           = 0xF0000000,      //为系统内部框架预留
    UIControlEventAllEvents                = 0xFFFFFFFF       //通知所有事件。
};

感谢文章:https://www.jianshu.com/p/7d7163a35133

如果您有什么疑问或者书写歧义,非常感激您能留言~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容