1字节存储多个布尔
位运算方式
通过位运算,将多个 BOOL
数值存储到一个 char
类型变量里:
// 掩码(Mask),一般用于按位运算,用于取出或修改特定二进制位的值
#define A_MASK (1<<0) // 0b0001
#define B_MASK (1<<1) // 0b0010
#define C_MASK (1<<2) // 0b0100
#define D_MASK (1<<3) // 0b1000
@interface Person () {
char _abcd; // 0b 0000 0000(规定存储位:0b 0000 dcba)
}
@end
@implementation Person
- (void)setA:(BOOL)a {
if (a) {
_abcd |= A_MASK;
} else {
_abcd &= ~A_MASK;
}
}
- (void)setB:(BOOL)b {
if (b) {
_abcd |= B_MASK;
} else {
_abcd &= ~B_MASK;
}
}
- (void)setC:(BOOL)c {
if (c) {
_abcd |= C_MASK;
} else {
_abcd &= ~C_MASK;
}
}
- (void)setD:(BOOL)d {
if (d) {
_abcd |= D_MASK;
} else {
_abcd &= ~D_MASK;
}
}
- (BOOL)a {
return !!(_abcd & A_MASK);
}
- (BOOL)b {
return !!(_abcd & B_MASK);
}
- (BOOL)c {
return !!(_abcd & C_MASK);
}
- (BOOL)d {
return !!(_abcd & D_MASK);
}
@end
位域方式
使用位域实现更方便,不过性能稍微低一点点:
@interface Person () {
// 结构体支持位域,: 后面的数值表示占用二进制位数
struct {
char a : 1;
char b : 1;
char c : 1;
char d : 1;
} _abcd; // 0b 0000 dcba; 先写的在最右边
}
@end
@implementation Person
- (void)setA:(BOOL)a {
_abcd.a = a;
}
- (void)setB:(BOOL)b {
_abcd.b = b;
}
- (void)setC:(BOOL)c {
_abcd.c = c;
}
- (void)setD:(BOOL)d {
_abcd.d = d;
}
- (BOOL)a {
return !!_abcd.a;
}
- (BOOL)b {
return !!_abcd.b;
}
- (BOOL)c {
return !!_abcd.c;
}
- (BOOL)d {
return !!_abcd.d;
}
@end
位运算+位域方式
也是通过位运算实现,位域增加可读性,同时也保证了性能:
#define A_MASK (1<<0) // 0b0001
#define B_MASK (1<<1) // 0b0010
#define C_MASK (1<<2) // 0b0100
#define D_MASK (1<<3) // 0b1000
@interface Person () {
// 共用体的所有成员,共用一块内存空间。也就是这个共用体也是1字节
union {
char bits; // 这个变量的大小要大于等于结构体的大小,才不会影响存储。比如结构体超过了8位,就不能用char类型,需要换更大的类型。
// 这个结构体只是为了增加可读性,表示bits里存储的内容。
struct {
char a : 1;
char b : 1;
char c : 1;
char d : 1;
};
} _abcd;
}
@end
@implementation Person
- (void)setA:(BOOL)a {
if (a) {
_abcd.bits |= A_MASK;
} else {
_abcd.bits &= ~A_MASK;
}
}
- (void)setB:(BOOL)b {
if (b) {
_abcd.bits |= B_MASK;
} else {
_abcd.bits &= ~B_MASK;
}
}
- (void)setC:(BOOL)c {
if (c) {
_abcd.bits |= C_MASK;
} else {
_abcd.bits &= ~C_MASK;
}
}
- (void)setD:(BOOL)d {
if (d) {
_abcd.bits |= D_MASK;
} else {
_abcd.bits &= ~D_MASK;
}
}
- (BOOL)a {
return !!(_abcd.bits & A_MASK);
}
- (BOOL)b {
return !!(_abcd.bits & B_MASK);
}
- (BOOL)c {
return !!(_abcd.bits & C_MASK);
}
- (BOOL)d {
return !!(_abcd.bits & D_MASK);
}
@end
掩码位数
上面都是用1
个二进制位来存储,如果要使用多个二进制位,掩码的宏定义就需要修改了。
1
个二进制位:
#define A_MASK (1<<0) // 0b0001
#define B_MASK (1<<1) // 0b0010
#define C_MASK (1<<2) // 0b0100
#define D_MASK (1<<3) // 0b1000
2
个二进制位:
#define A_MASK (0b0011<<0) // 0b00000011
#define B_MASK (0b0011<<1) // 0b00000110
#define C_MASK (0b0011<<2) // 0b00001100
#define D_MASK (0b0011<<3) // 0b00011000
多个二进制位也是相同的原理,需要多少个二进制位,就有多少个二进制位为1
。
NS_OPTIONS选项
OC
通过 NS_OPTIONS
定义枚举选项,通过位运算实现多个枚举值的合并拆分:
// 0x01 | 0x02 == 0b0001 | 0b0010 == 0b0011
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
// 0b0011 & 0b0001 == 0b0001
if (options & NSKeyValueObservingOptionNew) {
NSLog(@"NSKeyValueObservingOptionNew");
}
// 0b0011 & 0b0010 == 0b0010
if (options & NSKeyValueObservingOptionOld) {
NSLog(@"NSKeyValueObservingOptionOld");
}
// 0b0011 & 0b0100 != 0b0000
if (options & NSKeyValueObservingOptionInitial) {
NSLog(@"NSKeyValueObservingOptionInitial");
}
// 0b0011 & 0b1000 != 0b0000
if (options & NSKeyValueObservingOptionPrior) {
NSLog(@"NSKeyValueObservingOptionPrior");
}
// 增加选项
// 0b0011 | 0b0100 = 0b0111
options |= NSKeyValueObservingOptionInitial;
// 0b0111 & 0b0100 == 0b0100
if (options & NSKeyValueObservingOptionInitial) {
NSLog(@"增加后-NSKeyValueObservingOptionInitial");
}
// 减少选项
// 0b0111 & (~0b0100) = 0b0111 & 0b1011 = 0b0011
options &= ~NSKeyValueObservingOptionInitial;
// 0b0011 & 0b0100 != 0b0000
if (options & NSKeyValueObservingOptionInitial) {
NSLog(@"减少后-NSKeyValueObservingOptionInitial");
}
/**
最终打印
NSKeyValueObservingOptionNew
NSKeyValueObservingOptionOld
增加后-NSKeyValueObservingOptionInitial
*/