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

一、前言

位運算在我們實際開發(fā)中用得很少,主要原因還是它對于我們而言不好讀、不好懂、也不好計算,如果不經常實踐,很容易就生疏了。但實際上,位運算是一種很好的運算思想,它的優(yōu)點自然是計算快,代碼更少。

二、基本知識介紹

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

三、問題引用

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

這里,位掩碼的使用就可以巧妙的解決此問題。

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

8杯水分別編號.png

將該矩陣轉置,得:

水杯矩陣轉置.png

依上述場景,取4只容器,轉置后的矩陣數(shù)列配組合溶液:
取數(shù)位上為1的水,放入相應的容器,即:
第一杯:只包含8號水
第二杯:包含4、5、6、7號水
第三杯:包含2、3、6、7號水
第四杯:包含1、3、5、7號水

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

將1000瓶依次編號:1,2,3,4,...,1000; 且都記作二進制;
那我們要用多少位來表示呢?
總數(shù)是1000,2^9=512, 2^10=1024,于是至少要10位才夠表示,
也就是:0000000001,0000000010,0000000011,...,1111101000;
道理同上。

四、結合實際問題

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

  • 在實際開發(fā)中,我們常常遇到權限的判斷的問題,比如說,不同的用戶對系統(tǒng)有不同的操作權限,有的用戶可能有多種權限,我們最常規(guī)的辦法就是每一個權限定義一個BOOL值。
    假設,某系統(tǒng)有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同時擁有permission1、permission2、permission4怎么表示呢?

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

這樣的操作大家見多了吧?那我們來看看另一種寫法:

@interface BM_User : NSObject

@property (nonatomic, assign) OptionPermission permission;

@end

有人就要問了,OptionPermission是什么鬼?來,繼續(xù)。。。

/**
 權限枚舉

 - 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同時擁有permission1、permission2、permission4怎么表示呢?

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

是不是神清氣爽?

現(xiàn)在我們就具體化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 ()

/** 存儲目前的權限狀態(tài) */
@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;
}

五、寫在最后

  • 大家還可以自行搜索一下NS_OPTIONS與NS_ENUM的區(qū)別,他們都是用來定義枚舉的,但其用法是有很大不同。
  • 博主我最近一直在考慮優(yōu)化代碼,正在開發(fā)的項目中就有很多權限判斷的問題,我也在尋找各種各樣更好的寫法。
  • 也希望大家重視代碼的表達,因此更加優(yōu)化自己的代碼。
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,195評論 0 13
  • Bitwise Operation導語眾所周知計算機是基于二進制01進行運算的,理所當然地,位運算相對于各種算術運...
    曲水流觴TechRill閱讀 2,209評論 0 6
  • 今天在項目中遇到按位或組合權限串的問題: 首先每一個權限數(shù)都是2的N次方數(shù) 如:k1=2 ; //添加 k2=4...
    某人在閱讀 1,227評論 0 0
  • 2017-12-03 晴 早上起來就看見了暖暖的陽光,一個溫暖的周末。無拘無束的度過了一天的閑暇時光,午后...
    于勇i閱讀 301評論 0 0
  • 城破殘墻冷夜深,漠然置母歸黃泉 秦修在送完花輕煙后,極快的轉身回了內院,果然見杜錦官已經在等待了,面色陰沉,透著很...
    沅抒閱讀 410評論 8 10