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

一、前言

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

二、基本知識介紹

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

三、問題引用

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

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

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

8杯水分別編號.png

將該矩陣轉(zhuǎn)置,得:

水杯矩陣轉(zhuǎn)置.png

依上述場景,取4只容器,轉(zhuǎn)置后的矩陣數(shù)列配組合溶液:
取數(shù)位上為1的水,放入相應(yīng)的容器,即:
第一杯:只包含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
將二進(jìn)制數(shù)列wxyz轉(zhuǎn)為十進(jìn)制,則得到有毒水的號碼。
假設(shè)6號水有毒,那么往回推算,不難看出,第2、3只老鼠會死亡,
得到的wxyz的數(shù)列就是0110,轉(zhuǎn)十進(jìn)制后就是6。

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

四、結(jié)合實(shí)際問題

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

  • 在實(shí)際開發(fā)中,我們常常遇到權(quán)限的判斷的問題,比如說,不同的用戶對系統(tǒng)有不同的操作權(quán)限,有的用戶可能有多種權(quán)限,我們最常規(guī)的辦法就是每一個權(quán)限定義一個BOOL值。
    假設(shè),某系統(tǒng)有4種權(quán)限,那么,就有了:
@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ù)。。。

/**
 權(quán)限枚舉

 - 1: permission1,二進(jìn)制第1位,0表示否,1表示是
 - 2: permission2,二進(jìn)制第2位,0表示否,1表示是
 - 4: permission3,二進(jìn)制第3位,0表示否,1表示是
 - 8: permission4,二進(jìn)制第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種權(quán)限,并給出基礎(chǔ)位掩碼的表達(dá)及運(yùn)算:

#ifndef BM_Head_h
#define BM_Head_h

/**
 權(quán)限枚舉

 - 1: 是否允許查詢,二進(jìn)制第1位,0表示否,1表示是
 - 2: 是否允許新增,二進(jìn)制第2位,0表示否,1表示是
 - 4: 是否允許修改,二進(jìn)制第3位,0表示否,1表示是
 - 8: 是否允許刪除,二進(jìn)制第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 ()

/** 存儲目前的權(quán)限狀態(tài) */
@property (nonatomic, assign) OptionPermission flag;

@end

@implementation BM_Permission


/** 重新設(shè)置權(quán)限 */
- (void)setPermission:(OptionPermission)permission {
    self.flag = permission;
}

/** 添加一項(xiàng)或多項(xiàng)權(quán)限 */
- (void)enable:(OptionPermission)permission {
    self.flag |= permission;
}

/** 刪除一項(xiàng)或多項(xiàng)權(quán)限 */
- (void)disable:(OptionPermission)permission {
    self.flag &= ~permission;
}

/** 是否擁某些權(quán)限 */
- (BOOL)siAllow:(OptionPermission)permission {
    return (self.flag & permission) == permission;
}

/** 是否禁用了某些權(quán)限 */
- (BOOL)isNotAllow:(OptionPermission)permission {
    return (self.flag & permission) == 0;
}

/** 是否僅僅擁有某些權(quán)限 */
- (BOOL)isOnlyAllow:(OptionPermission)permission {
    return self.flag == permission;
}

五、寫在最后

  • 大家還可以自行搜索一下NS_OPTIONS與NS_ENUM的區(qū)別,他們都是用來定義枚舉的,但其用法是有很大不同。
  • 博主我最近一直在考慮優(yōu)化代碼,正在開發(fā)的項(xiàng)目中就有很多權(quán)限判斷的問題,我也在尋找各種各樣更好的寫法。
  • 也希望大家重視代碼的表達(dá),因此更加優(yōu)化自己的代碼。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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

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