位掩碼(BitMask)的介紹與使用

1、前言

位運算在咱們實際開發中用得不多,主要緣由仍是它對於咱們而言很差讀、很差懂、也很差計算,若是不常常實踐,很容易就生疏了。但實際上,位運算是一種很好的運算思想,它的優勢天然是計算快,代碼更少。優化

2、基本知識介紹

  • 二進制:
    二進制是由1和0兩個數字組成的,它能夠表示兩種狀態,即開和關。全部輸入電腦的任何信息最終都要轉化爲二進制。目前通用的是ASCII碼。最基本的單位爲bit。
  • 位運算:
    程序中的全部數在計算機內存中都是以二進制的形式儲存的。位運算說穿了,就是直接對整數在內存中的二進制位進行操做。好比,and運算原本是一個邏輯運算符,但整數與整數之間也能夠進行and運算。舉個例子,6的二進制是110,11的二進制是1011,那麼6 and 11的結果就是2,它是二進制對應位進行邏輯運算的結果(0表示False,1表示True,空位都當0處理)。

3、問題引用

  • 老鼠試毒
    有1000瓶水,其中有一瓶有毒,小白鼠只要嘗一點帶毒的水24小時後就會死亡,問至少要多少隻小白鼠才能在24小時內鑑別出哪瓶水有毒?
 
老鼠試毒.png

這裏,位掩碼的使用就能夠巧妙的解決此問題。atom

咱們先將問題簡化一下:假設只有8瓶水,其中1瓶有毒。spa

 
8杯水分別編號.png

將該矩陣轉置,得:code

 
水杯矩陣轉置.png

依上述場景,取4只容器,轉置後的矩陣數列配組合溶液:
取數位上爲1的水,放入相應的容器,即:
第一杯:只包含8號水
第二杯:包含四、五、六、7號水
第三杯:包含二、三、六、7號水
第四杯:包含一、三、五、7號水orm

取4只老鼠,編號一、二、三、4,分別喝下第一杯...第四杯水,
4只老鼠的生死狀態依次記爲 w x y z,(w,x,y,z = {0,1})
死亡記做1,非死亡記做0
將二進制數列wxyz轉爲十進制,則獲得有毒水的號碼。
假設6號水有毒,那麼往回推算,不難看出,第二、3只老鼠會死亡,
獲得的wxyz的數列就是0110,轉十進制後就是6。blog

將1000瓶依次編號:1,2,3,4,...,1000; 且都記做二進制;
那咱們要用多少位來表示呢?
總數是1000,2^9=512, 2^10=1024,因而至少要10位纔夠表示,
也就是:0000000001,0000000010,0000000011,...,1111101000;
道理同上。內存

4、結合實際問題

咱們已經見識了二進制的厲害之處了,接下來咱們結合代碼來看看,在iOS開發中的應用(其實在任何開發中都同樣)開發

  • 在實際開發中,咱們經常遇到權限的判斷的問題,好比說,不一樣的用戶對系統有不一樣的操做權限,有的用戶可能有多種權限,咱們最常規的辦法就是每個權限定義一個BOOL值。
    假設,某系統有4種權限,那麼,就有了:
@interface BM_User : NSObject
@property (nonatomic, assign) BOOL permission1;
@property (nonatomic, assign) BOOL permission2;
@property (nonatomic, assign) BOOL permission3;
@property (nonatomic, assign) BOOL permission4;
@end

那用戶A同時擁有permission一、permission二、permission4怎麼表示呢?it

    BM_User *userA = [[BM_User alloc] init];
    userA.permission1 = YES;
    userA.permission2 = YES;
    userA.permission4 = YES;

這樣的操做你們見多了吧?那咱們來看看另外一種寫法:io

@interface BM_User : NSObject
@property (nonatomic, assign) OptionPermission permission;
@end

有人就要問了,OptionPermission是什麼鬼?來,繼續。。。

/**
 權限枚舉

 - 1: permission1,二進制第1位,0表示否,1表示是
 - 2: permission2,二進制第2位,0表示否,1表示是
 - 4: permission3,二進制第3位,0表示否,1表示是
 - 8: permission4,二進制第4位,0表示否,1表示是
 */
typedef NS_OPTIONS(NSUInteger, OptionPermission) {
    permission1 = 1 << 0,//0001,1
    permission2 = 1 << 1,//0010,2
    permission3 = 1 << 2,//0100,4
    permission4 = 1 << 3,//1000,8
};

那用戶A同時擁有permission一、permission二、permission4怎麼表示呢?

    BM_User *userA = [[BM_User alloc] init];
    userA.permission = permission1 | permission2 | permission4;

是否是神清氣爽?

如今咱們就具體化4種權限,並給出基礎位掩碼的表達及運算:

#ifndef BM_Head_h
#define BM_Head_h
/**
 權限枚舉
 - 1: 是否容許查詢,二進制第1位,0表示否,1表示是
 - 2: 是否容許新增,二進制第2位,0表示否,1表示是
 - 4: 是否容許修改,二進制第3位,0表示否,1表示是
 - 8: 是否容許刪除,二進制第4位,0表示否,1表示是
 */
typedef NS_OPTIONS(NSUInteger, OptionPermission) {
    ALLOW_SELECT = 1 << 0,//0001,1
    ALLOW_INSERT = 1 << 1,//0010,2
    ALLOW_UPDATE = 1 << 2,//0100,4
    ALLOW_DELETE = 1 << 3,//1000,8
};
#endif /* BM_Head_h */
#import "BM_Permission.h"
#import "BM_Head.h"
@interface BM_Permission ()
/** 存儲目前的權限狀態 */
@property (nonatomic, assign) OptionPermission flag;
@end
@implementation BM_Permission
/** 從新設置權限 */
- (void)setPermission:(OptionPermission)permission {
    self.flag = permission;
}
/** 添加一項或多項權限 */
- (void)enable:(OptionPermission)permission {
    self.flag |= permission;
}
/** 刪除一項或多項權限 */
- (void)disable:(OptionPermission)permission {
    self.flag &= ~permission;
}
/** 是否擁某些權限 */
- (BOOL)siAllow:(OptionPermission)permission {
    return (self.flag & permission) == permission;
}
/** 是否禁用了某些權限 */
- (BOOL)isNotAllow:(OptionPermission)permission {
    return (self.flag & permission) == 0;
}
/** 是否僅僅擁有某些權限 */
- (BOOL)isOnlyAllow:(OptionPermission)permission {
    return self.flag == permission;
}

5、寫在最後

  • 你們還能夠自行搜索一下NS_OPTIONS與NS_ENUM的區別,他們都是用來定義枚舉的,但其用法是有很大不一樣。
  • 博主我最近一直在考慮優化代碼,正在開發的項目中就有不少權限判斷的問題,我也在尋找各類各樣更好的寫法。
  • 也但願你們重視代碼的表達,所以更加優化本身的代碼。

做者:Leewins連接:https://www.jianshu.com/p/4e73512c03b8

相關文章
相關標籤/搜索