美文网首页
iOS 位运算

iOS 位运算

作者: 陈盼同学 | 来源:发表于2021-01-29 16:55 被阅读0次
//用来按位与(&)或者或(|)运算的,一般定义的宏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];
}

相关文章

  • IOS 位运算

  • iOS位运算

    位运算符使用的运算符包括下面: 1、<< 1<<1 指的是 0001 << 1 左移1位 0010 值修改为2 2...

  • ios 位运算

    1,左移运算符 << (右移雷同) 公式 x << 3 就是把x的各二进位左移3位 1<<1 实际就是 0001 ...

  • iOS 位运算

    与运算 或运算 我们新建一个MJPerson类,类里声明如下属性 这时候系统会给tall和rich生成set方法,...

  • iOS 位运算

    1 左移运算符 <<按位移 公式 x <<3 就是把x的各二进位左移3位 1 << 1 实际就是 0001 << ...

  • iOS开发-位运算

    http://www.jianshu.com/p/36ba5d65804f

  • iOS位运算实例

    这段代码是不是很眼熟? 这段代码在做APNS推送时有用到,需要设置推送的提醒方式,这里的意思是,提醒方式为:徽标或...

  • iOS开发-位运算

    前言 从现代计算机电路来说,只有高电平/低电平两种状态,即为0/1状态,计算机中所有的数据按照具体的编码格式以二进...

  • iOS 性能优化之位域,联合体,位运算的使用,节省空间

    iOS 性能优化之位域,共用体,位运算的使用,节省空间 1. 位运算方法 测试代码 我们是利用了一个 char 一...

  • iOS中位运算详解

    本文主要讲解三个运算符 左移(<<)、与(&)、或(|) 在iOS代码中如何使用。 我们经常能看到下面这样的代码 ...

网友评论

      本文标题:iOS 位运算

      本文链接:https://www.haomeiwen.com/subject/whvgzktx.html