位掩码(BitMask)的介绍与使用

一、前言

位运算在我们实际开发中用得很少,主要原因还是它对于我们而言不好读、不好懂、也不好计算,如果不经常实践,很容易就生疏了。但实际上,位运算是一种很好的运算思想,它的优点自然是计算快,代码更少。

二、基本知识介绍

  • 二进制:
    二进制是由1和0两个数字组成的,它可以表示两种状态,即开和关。所有输入电脑的任何信息最终都要转化为二进制。目前通用的是ASCII码。最基本的单位为bit。
  • 位运算:
    程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理)。

三、问题引用

  • 老鼠试毒
    有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,问至少要多少只小白鼠才能在24小时内鉴别出哪瓶水有毒?
老鼠试毒.png

这里,位掩码的使用就可以巧妙的解决此问题。

我们先将问题简化一下:假设只有8瓶水,其中1瓶有毒。

8杯水分别编号.png

将该矩阵转置,得:

水杯矩阵转置.png

依上述场景,取4只容器,转置后的矩阵数列配组合溶液:
取数位上为1的水,放入相应的容器,即:
第一杯:只包含8号水
第二杯:包含4、5、6、7号水
第三杯:包含2、3、6、7号水
第四杯:包含1、3、5、7号水

取4只老鼠,编号1、2、3、4,分别喝下第一杯...第四杯水,
4只老鼠的生死状态依次记为 w x y z,(w,x,y,z = {0,1})
死亡记作1,非死亡记作0
将二进制数列wxyz转为十进制,则得到有毒水的号码。
假设6号水有毒,那么往回推算,不难看出,第2、3只老鼠会死亡,
得到的wxyz的数列就是0110,转十进制后就是6。

将1000瓶依次编号:1,2,3,4,...,1000; 且都记作二进制;
那我们要用多少位来表示呢?
总数是1000,2^9=512, 2^10=1024,于是至少要10位才够表示,
也就是:0000000001,0000000010,0000000011,...,1111101000;
道理同上。

四、结合实际问题

我们已经见识了二进制的厉害之处了,接下来我们结合代码来看看,在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同时拥有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是什么鬼?来,继续。。。

/**
 权限枚举

 - 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;

是不是神清气爽?

现在我们就具体化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;
}

五、写在最后

  • 大家还可以自行搜索一下NS_OPTIONS与NS_ENUM的区别,他们都是用来定义枚举的,但其用法是有很大不同。
  • 博主我最近一直在考虑优化代码,正在开发的项目中就有很多权限判断的问题,我也在寻找各种各样更好的写法。
  • 也希望大家重视代码的表达,因此更加优化自己的代码。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,132评论 0 13
  • Bitwise Operation导语众所周知计算机是基于二进制01进行运算的,理所当然地,位运算相对于各种算术运...
    曲水流觞TechRill阅读 2,165评论 0 6
  • 今天在项目中遇到按位或组合权限串的问题: 首先每一个权限数都是2的N次方数 如:k1=2 ; //添加 k2=4...
    某人在阅读 1,206评论 0 0
  • 2017-12-03 晴 早上起来就看见了暖暖的阳光,一个温暖的周末。无拘无束的度过了一天的闲暇时光,午后...
    于勇i阅读 295评论 0 0
  • 城破残墙冷夜深,漠然置母归黄泉 秦修在送完花轻烟后,极快的转身回了内院,果然见杜锦官已经在等待了,面色阴沉,透着很...
    沅抒阅读 390评论 8 10