//用来按位与(&)或者或(|)运算的,一般定义的宏mask被称为掩码,
MASK
与运算
//&可以用来取出特定的位
0000 0111
& 0000 0100
------ (同为1与后为1,同为0与后为0,否则与后为0)
0000 0100
或运算
0010 1010
| 1111 1100
----------(只要有一个为1则为1,否则或后为0)
1111 1110
我们新建一个MJPerson类,类里声明如下属性
@property (assign, nonatomic, getter=isTall) BOOL tall;
@property (assign, nonatomic, getter=isRich) BOOL rich;
@property (assign, nonatomic, getter=isHansome) BOOL handsome;
这时候系统会给tall和rich生成set方法,get方法,_成员变量,tall占用1字节,rich占用1字节,handsome占用1字节。因为他俩是bool值,只有0和1两种结果,所以三个二进制位就能表示了,并不需要三个字节,导致内存会浪费。所以我们把@property属性删除了,手动实现set和get改进程序。
.h文件
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
//@property (assign, nonatomic, getter=isTall) BOOL tall;
//@property (assign, nonatomic, getter=isRich) BOOL rich;
//@property (assign, nonatomic, getter=isHansome) BOOL handsome;
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end
.m文件
#import "MJPerson.h"
// 掩码,一般用来按位与(&)运算的
//#define MJTallMask 1
//#define MJRichMask 2
//#define MJHandsomeMask 4
//进化
//#define MJTallMask 0b00000001 (0b代表二进制)
//#define MJRichMask 0b00000010
//#define MJHandsomeMask 0b00000100
//再进化
#define MJTallMask (1<<0) //用括号括起来是让括号内先运算防止被外界运算符错误计算
#define MJRichMask (1<<1)
#define MJHandsomeMask (1<<2)
@interface MJPerson()
{
char _tallRichHansome;
}
@end
@implementation MJPerson
- (instancetype)init
{
if (self = [super init]) {
_tallRichHansome = 0b00000000;
}
return self;
}
- (void)setTall:(BOOL)tall
{
if (tall) {
_tallRichHansome |= MJTallMask; //按位或,能够把当前位存进去
} else {
//~按位取反
_tallRichHansome &= ~MJTallMask; //先把掩码按位取反,然后就能确保要存进去的这位置为0,其他位都为1,然后按位与,就能保证其他位置原来是什么现在还是什么,传进来的值再与上0还是零,于是能够把当前位存进去。
}
}
- (BOOL)isTall
{
//因为要取出某一位,所以括号里的值&出来后要么为0要么有值。第一个!是将括号里的条件(有值就是真,无值就是0)变成bool取反,第二个!再次取反
return !!(_tallRichHansome & MJTallMask);
}
- (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHansome |= MJRichMask;
} else {
_tallRichHansome &= ~MJRichMask;
}
}
- (BOOL)isRich
{
return !!(_tallRichHansome & MJRichMask);
}
- (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHansome |= MJHandsomeMask;
} else {
_tallRichHansome &= ~MJHandsomeMask;
}
}
- (BOOL)isHandsome
{
return !!(_tallRichHansome & MJHandsomeMask);
}
@end
经过上述的改造后,内存占用变小,调用person依旧能改里面的bool值
MJPerson *person = [[MJPerson alloc] init];
person.rich = YES;
person.tall = YES;
person.handsome = YES;
NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
我们针对上面的person类的代码再次改造
.h文件
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
//@property (assign, nonatomic, getter=isTall) BOOL tall;
//@property (assign, nonatomic, getter=isRich) BOOL rich;
//@property (assign, nonatomic, getter=isHansome) BOOL handsome;
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end
.m文件
#import "MJPerson.h"
@interface MJPerson()
{
//结构体支持位域技术。
struct {
/*
位域的形式为
类型说明符 位域名:位域长度
先写的排在右边,比如下面三位就是 handsome rich tall
*/
char tall : 1; //(:1代表这个东西只占1位)
char rich : 1; //(:1代表这个东西只占1位)
char handsome : 1; //(:1代表这个东西只占1位)
} _tallRichHandsome; //_tallRichHandsome是成员变量名字,左边结构体是成员变量的名字。
}
@end
@implementation MJPerson
- (void)setTall:(BOOL)tall
{
_tallRichHandsome.tall = tall;
}
- (BOOL)isTall
{
return !!_tallRichHandsome.tall;
//为什么存可以直接存,取却不可以直接取呢?
//因为BOOL是8位,如果直接取 return _tallRichHandsome.tall;的话相当于取出来0b1,只有1位,那么这1位要怎么转换为8位呢,会逐位向左拉伸覆盖,就这个值而言,会覆盖位0b11111111
}
- (void)setRich:(BOOL)rich
{
_tallRichHandsome.rich = rich;
}
- (BOOL)isRich
{
return !!_tallRichHandsome.rich;
}
- (void)setHandsome:(BOOL)handsome
{
_tallRichHandsome.handsome = handsome;
}
- (BOOL)isHandsome
{
return !!_tallRichHandsome.handsome;
}
@end
话外:255和-1在内存中都是存储为0xFF,有符号数就是255,无符号数就是-1
共用体
union { //union共同体,共用一块内存,因为这个共用体里有两个元素,其中int4字节,char1字节,所以这个共用体就是最大的成员占用量4字节,其中char占用1字节,会影响int4字节里的1位。
int age;
char bits;
};
我们针对上面的person类的代码再次改造。改造成刚才那种通过位运算的形式
.h文件
#import <Foundation/Foundation.h>
@interface MJPerson : NSObject
//@property (assign, nonatomic, getter=isTall) BOOL tall;
//@property (assign, nonatomic, getter=isRich) BOOL rich;
//@property (assign, nonatomic, getter=isHansome) BOOL handsome;
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end
.m文件
#import "MJPerson.h"
#define MJTallMask (1<<0)
#define MJRichMask (1<<1)
#define MJHandsomeMask (1<<2)
@interface MJPerson()
{
union { //union共同体,共用一块内存 ,所以整体下来_tallRichHandsome只会分配1字节
char bits;
struct {//这结构体是摆设,只是为了提示bits位运算时操作的对应为对应的是什么。
char tall : 1; //这三个东西是摆设,只是为了更直观的展示而已,方便的看bits位运算时操作的每一位对应的是什么。
char rich : 1; //这三个东西是摆设,只是为了更直观的展示而已
char handsome : 1; //这三个东西是摆设,只是为了更直观的展示而已
};
} _tallRichHandsome;
}
@end
@implementation MJPerson
- (void)setTall:(BOOL)tall
{
if (tall) {
_tallRichHandsome.bits |= MJTallMask;
} else {
_tallRichHandsome.bits &= ~MJTallMask;
}
}
- (BOOL)isTall
{
return !!(_tallRichHandsome.bits & MJTallMask);
}
- (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHandsome.bits |= MJRichMask;
} else {
_tallRichHandsome.bits &= ~MJRichMask;
}
}
- (BOOL)isRich
{
return !!(_tallRichHandsome.bits & MJRichMask);
}
- (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHandsome.bits |= MJHandsomeMask;
} else {
_tallRichHandsome.bits &= ~MJHandsomeMask;
}
}
- (BOOL)isHandsome
{
return !!(_tallRichHandsome.bits & MJHandsomeMask);
}
@end
位运算小例子设计
//
#import "ViewController.h"
//typedef enum {
// MJOptionsOne = 1, // 0b0001
// MJOptionsTwo = 2, // 0b0010
// MJOptionsThree = 4, // 0b0100
// MJOptionsFour = 8 // 0b1000
//} MJOptions;
typedef enum {
// MJOptionsNone = 0, // 0b0000
MJOptionsOne = 1<<0, // 0b0001
MJOptionsTwo = 1<<1, // 0b0010
MJOptionsThree = 1<<2, // 0b0100
MJOptionsFour = 1<<3 // 0b1000
} MJOptions;
@interface ViewController ()
@end
@implementation ViewController
/*
0b0001
0b0010
0b1000
------
0b1011
&0b0100
-------
0b0000
*/
- (void)setOptions:(MJOptions)options
{
if (options & MJOptionsOne) {
NSLog(@"包含了MJOptionsOne");
}
if (options & MJOptionsTwo) {
NSLog(@"包含了MJOptionsTwo");
}
if (options & MJOptionsThree) {
NSLog(@"包含了MJOptionsThree");
}
if (options & MJOptionsFour) {
NSLog(@"包含了MJOptionsFour");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
//下面两种都行
[self setOptions: MJOptionsOne | MJOptionsFour];
[self setOptions: MJOptionsOne + MJOptionsTwo + MJOptionsFour];
}
网友评论