/**
*
* 0000 0111
* & 0000 0010
*-------------
* 0000 0010
*
* 二进制转Bool类型需要两次取反(!!)
*/
2.1、当设置值为1时
掩码 + 位或(|)运算。
/**
* 0000 0101
* | 0000 0010
*-------------
* 0000 0111
*/
2.2、当设置值为0时
掩码取反(~) + 再进行位与(&)运算。
/**
* 0000 0111
* & 1111 1101
*-------------
* 0000 0101
*/
知道了位运算的基本规则,下面用几个例子,来了解一下位运算在OC中的应用:
===========================================================================
这里我们就用高富帅(tall、rich、handsome)的取值和赋值方法,作为举例。
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
// 高
- (BOOL)tall;
// 富
- (BOOL)rich;
// 帅
- (BOOL)handsome;
@end
Person.m
// 1、10进制位赋值
//#define kTallMask 1
//#define kRichMask 2
//#define kHandsomeMask 4
// 2、2进制位赋值,0b:表示2进制位
//#define kTallMask 0b00000001
//#define kRichMask 0b00000010
//#define kHandsomeMask 0b00000100
// 3、运算符赋值
#define kTallMask (1<<0)
#define kRichMask (1<<1)
#define kHandsomeMask (1<<2)
@interface Person(){
// char:长度一个字节(8个二进制位)
char _tallRichHandsome;// 0b 0000 0000
}
@end
@implementation Person
- (void)setTall:(BOOL)tall {
if (tall) {
// 掩码,位或(|)运算
_tallRichHandsome |= kTallMask;
} else {
//掩码取反,进行位与(&)运算
_tallRichHandsome &= ~kTallMask;
}
}
- (void)setRich:(BOOL)rich {
if (rich) {
_tallRichHandsome |= kRichMask;
} else {
_tallRichHandsome &= ~kRichMask;
}
}
- (void)setHandsome:(BOOL)handsome {
if (handsome) {
_tallRichHandsome |= kHandsomeMask;
} else {
_tallRichHandsome &= ~kHandsomeMask;
}
}
- (BOOL)tall {
// 掩码,位与(&)运算:两次取反(!!)返回Bool类型
return !!(_tallRichHandsome & kTallMask);
}
- (BOOL)rich {
return !!(_tallRichHandsome & kRichMask);
}
- (BOOL)handsome {
return !!(_tallRichHandsome & kHandsomeMask);
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Leader *person = [[Leader alloc] init];
person.tall = YES;
person.rich = YES;
person.handsome = YES;
NSLog(@"-------tall:%hhd",person.tall);
NSLog(@"-------rich:%hhd",person.rich);
NSLog(@"-------handsome:%hhd",person.handsome);
}
return 0;
}
1、mask标记:表示掩码,一般用来位运算的。
2、掩码(mask)赋值有多种方式:
1、可以用10进制位赋值的。
2、用2进制位赋值的。
3、位移运算符赋值的,这里会用到左移运算符(<<)。
其中位移运算符赋值是最简单直观的,推荐使用这种方式。
3、掩码 + 位与(&)运算转Bool类型,需要两次取反(!!)。
=============================================================================
#import <Foundation/Foundation.h>
@interface Student : NSObject
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)tall;
- (BOOL)rich;
- (BOOL)handsome;
@end
#import "Student.h"
@interface Student(){
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
}_tallRichHandsome;
}
@end
@implementation Student
- (instancetype)init {
if (self = [super init]) {
}
return self;
}
- (void)setTall:(BOOL)tall {
_tallRichHandsome.tall = tall;
}
- (void)setRich:(BOOL)rich {
_tallRichHandsome.rich = rich;
}
- (void)setHandsome:(BOOL)handsome {
_tallRichHandsome.handsome = handsome;
}
- (BOOL)tall {
return !!_tallRichHandsome.tall;
}
- (BOOL)rich {
return !!_tallRichHandsome.rich;
}
- (BOOL)handsome {
return !!_tallRichHandsome.handsome;
}
当取值的时候,如果用如下方式实现:
- (BOOL)handsome {
return _tallRichHandsome.handsome;
}
发现,取值时打印出来为-1,实际二进制值为(0b1111 1111),这不是我们想要的结果,怎么处理?
/**
* tallRichHandsome.tall = 0b1 一个二进制位
* BOOL = 0b0000 0000 一个字节为8个二进制位
* ----------------------------------------------------------
* 结果 = 0b1111 1111 = 255(-1)
* 分析:当一个二进制位赋值给一个8个二进制位时,前面不足的拿最左边值(1)的填补。
*/
那么这个问题这么处理呢?
1、取值时,因为拿到的是bool类型,可以两个取反获取到想要的值(如上面👆的例子)。
第一次取反,只要不等于0,返回的都是false,二次取反,得到我们需要的值true。
2、根据位于临近填补的特点,设置占位为两位(如:0b01),得到的就是:0b0000 0001
=============================================================================
根据上面的问题处理,这里只要修改如下部分代码:
@interface Student(){
struct {// 结构体位域长度设置为2
char tall : 2;
char rich : 2;
char handsome : 2;
}_tallRichHandsome;
}
@end
// 取值不在需要二次取反
- (BOOL)tall {
return _tallRichHandsome.tall;
}
缺点:
结构体位域存储方式,变量在结构体中的位置,直接决定了在二进制中的存储位置。如代码有增删改操作,容易定位不准确,导致出错。
============================================================================
这是OC内部底层实现的逻辑。
#import <Foundation/Foundation.h>
@interface Leader : NSObject
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)tall;
- (BOOL)rich;
- (BOOL)handsome;
@end
#import "Leader.h"
#define kTallMask (1<<0)
#define kRichMask (1<<1)
#define kHandsomeMask (1<<2)
@interface Leader(){
union {// 共用体:大家都共用一个字节
char bits;//位
struct {// 结构体仅是提高代码可读性,没有实际应用
char tall : 1;
char rich : 1;
char handsome : 1;
};
}_tallRichHandsome;
}
@end
@implementation Leader
- (void)setTall:(BOOL)tall {
if (tall) {
_tallRichHandsome.bits |= kTallMask;
} else {
_tallRichHandsome.bits &= ~kTallMask;
}
}
- (void)setRich:(BOOL)rich {
if (rich) {
_tallRichHandsome.bits |= kRichMask;
} else {
_tallRichHandsome.bits &= ~kRichMask;
}
}
- (void)setHandsome:(BOOL)handsome {
if (handsome) {
_tallRichHandsome.bits |= kHandsomeMask;
} else {
_tallRichHandsome.bits &= ~kHandsomeMask;
}
}
- (BOOL)tall {
return !!(_tallRichHandsome.bits & kTallMask);
}
- (BOOL)rich {
return !!(_tallRichHandsome.bits & kRichMask);
}
- (BOOL)handsome {
return !!(_tallRichHandsome.bits & kHandsomeMask);
}
@end
这是位运算与结构体的位域结合方式,利用各自的优势。
那有什么优势呢?
1、位运算:定位精准,提高运算效率。
2、结构体的位域:提高代码的可读性。
===========================================================================