一、前言
位運算在我們實際開發(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小時內鑒別出哪瓶水有毒?
這里,位掩碼的使用就可以巧妙的解決此問題。
我們先將問題簡化一下:假設只有8瓶水,其中1瓶有毒。
將該矩陣轉置,得:
依上述場景,取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)化自己的代碼。