Runtime系列位运算在OC的取值和赋值01
✅作者简介:大家好我是瓜子三百克,一个非科班出身的技术程序员,还是喜欢在学习和开发中记录笔记的小白博主!
📃个人主页:瓜子三百克的主页
🔥系列专栏:OC语法
💖如果觉得博主的文章还不错的话,请点赞👍 收藏⭐️ 留言📝支持一下博主哦🤞
本片文章介绍将数据(如:Bool类型的数据)存储到二进制位中,包括实现逻辑、代码示例以及各自的优缺点分析。
一、实现逻辑
我们可以用简单的Bool类型,来实现数据在二进制中的取值和赋值:
1、取值
掩码 位与(&)运算。
/**
*
* 0000 0111
* & 0000 0010
*-------------
* 0000 0010
*
* 二进制转Bool类型需要两次取反(!!)
*/
2、赋值
2.1、当设置值为1时
掩码 位或(|)运算。
/**
* 0000 0101
* | 0000 0010
*-------------
* 0000 0111
*/
2.2、当设置值为0时
掩码取反(~) 再进行位与(&)运算。
/**
* 0000 0111
* & 1111 1101
*-------------
* 0000 0101
*/
知道了位运算的基本规则,下面用几个例子,来了解一下位运算在OC中的应用:
二、位运算符赋值
这里我们就用高富帅(tall、rich、handsome)的取值和赋值方法,作为举例。
2.1、代码示例
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;
}
2.2、结果分析
1、mask标记:表示掩码,一般用来位运算的。
2、掩码(mask)赋值有多种方式:
1、可以用10进制位赋值的。
2、用2进制位赋值的。
3、位移运算符赋值的,这里会用到左移运算符(<<)。
其中位移运算符赋值是最简单直观的,推荐使用这种方式。
3、掩码 位与(&)运算转Bool类型,需要两次取反(!!)。
三、结构体 位域实现
3.1、代码示例
#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;
}
3.2、分析
当取值的时候,如果用如下方式实现:
- (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内部底层实现的逻辑。
5.1、代码示例
#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
5.2、分析
这是位运算与结构体的位域结合方式,利用各自的优势。
那有什么优势呢?
1、位运算:定位精准,提高运算效率。
2、结构体的位域:提高代码的可读性。
六、OC中的应用
1、ISA_MASK
1、在arm64架构以前,isa指针就是一个普通的指针,存储着Class、Meta-Class对象的内存地址。
2、从arm64架构开始,对isa进行了优化,变成了一个共用体(union
)结构,还使用位域存储了更多信息。需要 &ISA_MASK 才能得到Class、Meta-Class对象的内存地址。
# define ISA_MASK 0x0000000ffffffff8ULL
2、enum枚举
在OC中最常见的位运算是枚举设置
// 枚举设施孩子
typedef enum {
ZMOptionsNone = 0,
ZMOptionsOne = 1<<0,// 0b0001
ZMOptionsTwo = 1<<1,// 0b0010
ZMOptionsThree = 1<<2,// 0b0100
ZMOptionsFour = 1<<3,// 0b1000
}ZMOptions;
// 取值
- (void)setOptions:(ZMOptions)options {
if (options&ZMOptionsOne) {
NSLog(@"ZMOptionsOne");
}
if (options&ZMOptionsTwo) {
NSLog(@"ZMOptionsTwo");
}
if (options&ZMOptionsThree) {
NSLog(@"ZMOptionsThree");
}
if (options&ZMOptionsFour) {
NSLog(@"ZMOptionsFour");
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// 赋值
[self setOptions:ZMOptionsOne|ZMOptionsFour];
}
**🏆结束语🏆 **
最后如果觉得我写的文章对您有帮助的话,欢迎点赞✌,收藏✌,加关注✌哦,谢谢谢谢!!
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgabbea
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24