美文网首页iOS 其他
多少人跪求的iOS NS_OPTIONS , 1 <<

多少人跪求的iOS NS_OPTIONS , 1 <<

作者: SmallWhiteMouse | 来源:发表于2018-04-11 17:08 被阅读937次

    一、这是个什么东西?

    • 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

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

    相关文章

      网友评论

        本文标题:多少人跪求的iOS NS_OPTIONS , 1 <<

        本文链接:https://www.haomeiwen.com/subject/vyzahftx.html