iOS - Runtime-isa详解(位域、union(共用体)、位运算)

news2024/11/13 9:52:46

文章目录

  • iOS - Runtime-isa详解(位域、union(共用体)、位运算)
    • 前言
    • 1. `位域`介绍
      • 1.1 思路
      • 1.2 示例 - 结构体
      • 1.3 示例 - union(共用体)
        • 1.3.1 说明
      • 1.4 结构体 对比 union(共用体)
    • 2. arm64架构对isa的优化
      • 2.1 位域内容
        • nonpointer
        • has_assoc
        • has_cxx_dtor
        • shiftcls
        • magic
        • weakly_referenced
        • deallocating
        • extra_rc
        • has_sidetable_rc
      • 2.2 Class、Meta-Class对象存储位置
    • 3. 拓展
      • 3.1 枚举值设计
      • 3.1.1 案例
      • 3.1.2 原理分析

iOS - Runtime-isa详解(位域、union(共用体)、位运算)

前言

本章主要了解Runtime相关内容,苹果对isa做了哪些优化,位域、union(共用体)又是如何运用的

  • 要想学习Runtime,首先要了解它底层的一些常用数据结构,比如isa指针
  • 在arm64架构之前,isa就是一个普通的指针,存储着ClassMeta-Class对象的内存地址
  • 从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息

1. 位域介绍

利用好位域的话,可以使程序运行高效节省内存,操作系统级别的东西很多都会使用

在IM系统的开发中,就使用了位域来对数据进行优化,后续有时间再抽出案例聊聊。

欢迎点赞,收藏,加关注!,谢谢你!!

1.1 思路

假如ZSXPerson类需要3个BOOL类型的属性,这时候我们通常会直接使用@property声明3个属性,这时候系统会给我们生成 3个_开头的成员变量,3对getset方法,所占据的内存也比较多

思路:BOOL 类型属性值要么 YES 要么 NO,使用字节中的一个(0或者1)其实就能表示一个 BOOL 类型的属性值,一个字节就可以表示8个 BOOL 值

1.2 示例 - 结构体

ZSXPerson.h

@interface ZSXPerson : NSObject

- (void)setTall:(BOOL)tall;

- (BOOL)isTall;

- (void)setRich:(BOOL)rich;

- (BOOL)isRich;

- (void)setHandsome:(BOOL)handsome;

- (BOOL)isHandsome;

@end

ZSXPerson.m

@interface ZSXPerson() {
    struct {
        char tall: 1;
        char rich: 1;
        char handsome: 1;
    } _tallRichHandsome;
}

@end

@implementation ZSXPerson

- (void)setTall:(BOOL)tall {
    _tallRichHandsome.tall = tall;
}

- (BOOL)isTall {
    return !!_tallRichHandsome.tall;
}

- (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

main.m

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.tall = NO;
        person.rich = YES;
        person.handsome = YES;
        
        NSLog(@"tall:%d  rich:%d  handsome:%d", person.isTall, person.isRich, person.isHandsome);
    }
    return 0;
}

运行结果:

1.3 示例 - union(共用体)

ZSXPerson.h

@interface ZSXPerson : NSObject

- (void)setTall:(BOOL)tall;

- (BOOL)isTall;

- (void)setRich:(BOOL)rich;

- (BOOL)isRich;

- (void)setHandsome:(BOOL)handsome;

- (BOOL)isHandsome;

@end

ZSXPerson.h.m

#import "ZSXPerson.h"

#define ZSXTallMask (1)
#define ZSXRichMask (1 << 1)
#define ZSXHandsomeMask (1 << 2)

@interface ZSXPerson() {
    union {
        char bits;
        struct {
            char tall: 1;
            char rich: 1;
            char handsome: 1;
        };
    }_tallRichHandsome;
}

@end

@implementation ZSXPerson

- (void)setTall:(BOOL)tall {
    if (tall) {
        _tallRichHandsome.bits |= ZSXTallMask;
    }
    else {
        _tallRichHandsome.bits &= ~ZSXTallMask;
    }
}

- (BOOL)isTall {
    return !!(_tallRichHandsome.bits & ZSXTallMask);
}

- (void)setRich:(BOOL)rich {
    if (rich) {
        _tallRichHandsome.bits |= ZSXRichMask;
    }
    else {
        _tallRichHandsome.bits &= ~ZSXRichMask;
    }
}

- (BOOL)isRich {
    return !!(_tallRichHandsome.bits & ZSXRichMask);
}

- (void)setHandsome:(BOOL)handsome {
    if (handsome) {
        _tallRichHandsome.bits |= ZSXHandsomeMask;
    }
    else {
        _tallRichHandsome.bits &= ~ZSXHandsomeMask;
    }
}

- (BOOL)isHandsome {
    return !!(_tallRichHandsome.bits & ZSXHandsomeMask);
}

@end

main.m

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.tall = NO;
        person.rich = YES;
        person.handsome = YES;
        
        NSLog(@"tall:%d  rich:%d  handsome:%d", person.isTall, person.isRich, person.isHandsome);
    }
    return 0;
}

运行结果:

1.3.1 说明

1.4 结构体 对比 union(共用体)

  • 结构体的成员是各自占用各自所需大小
  • 共同体的内存大小取决于其中最大的成员的大小,所有成员共用这块内存

  • 使用共用体实际上还是通过位运算来控制每个属性所占位置
  • 其中的sturct目的是增加可读性,实际上不会影响属性所占位置

2. arm64架构对isa的优化

arm64架构对isa中,使用一个64位的共用体来存储更多的信息,通过位域的概念来表示各个存储的信息的存储位置。其中有33位拿来存储Class、Meta-Class地址值


2.1 位域内容

nonpointer
  • 0,代表普通的指针,存储着Class、Meta-Class对象的内存地址
  • 1,代表优化过,使用位域存储更多的信息
has_assoc
  • 是否有设置过关联对象,如果没有,释放时会更快
has_cxx_dtor
  • 是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
shiftcls
  • 存储着Class、Meta-Class对象的内存地址信息
magic
  • 用于在调试时分辨对象是否未完成初始化
weakly_referenced
  • 是否有被弱引用指向过,如果没有,释放时会更快
deallocating
  • 对象是否正在释放
extra_rc
  • 里面存储的值是引用计数器减1
has_sidetable_rc
  • 引用计数器是否过大无法存储在isa中
  • 如果为1,那么引用计数会存储在一个叫SideTable的类的属性中

2.2 Class、Meta-Class对象存储位置

Class、Meta-Class对象存储在shiftcls,从上图可知shiftcls是从第4位开始,连续33

isa的掩码:define ISA_MASK 0x0000000ffffffff8ULL

将掩码转为二进制查看

它表示的就是从第4位开始,连续33位,通过这个掩码,就可以将Class、Meta-Class地址值取出来

Class、Meta-Class地址值后三位永远是 0。因为他的掩码左右边 3位是 0,&运算后一定是 0

3. 拓展

3.1 枚举值设计

在iOS中,系统的一些API可以使用|传入多个枚举值,比如:

self.view.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;

原理就是使用位域设计枚举值,然后通过位运算来取值

3.1.1 案例

我们也自己来设计一个这样的枚举

定义枚举:

typedef NS_OPTIONS(NSUInteger, ZSXOptions) {
    ZSXOptions1                 = 1 << 0, // 0b00000001
    ZSXOptions2                 = 1 << 1, // 0b00000010
    ZSXOptions3                 = 1 << 2, // 0b00000100
    ZSXOptions4                 = 1 << 3, // 0b00001000
    ZSXOptions5                 = 1 << 4, // 0b00010000
};

设置值方法:

- (void)setOptions:(ZSXOptions)options {
    if (options & ZSXOptions1) {
        NSLog(@"包含了ZSXOptions1");
    }
    
    if (options & ZSXOptions2) {
        NSLog(@"包含了ZSXOptions2");
    }
    
    if (options & ZSXOptions3) {
        NSLog(@"包含了ZSXOptions3");
    }
    
    if (options & ZSXOptions4) {
        NSLog(@"包含了ZSXOptions4");
    }
    
    if (options & ZSXOptions5) {
        NSLog(@"包含了ZSXOptions5");
    }
}

使用:

[self setOptions:ZSXOptions1 | ZSXOptions3 | ZSXOptions5];

打印如下:

此时我们已经实现了一个可以传入多个枚举值的接口

3.1.2 原理分析

/**
 0b00000001
 0b00000100
 0b00010000
 ----------------- | 运算(设置值)
 0b00010101
 
 0b00000001
 ----------------- & 运算(取值)
 0b00000001    为 true
 */

@oubijiexi

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1544648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python--罗马数字转换阿拉伯数字】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 罗马数字转换阿拉伯数字相关 根据长度给出罗马序列的值生成字典根据长度给出罗马序列的值生成列表将所有…

酷开系统让用户和电视双向传递,酷开科技实现商业变现

电视在我们的日常生活中扮演着重要的角色。虽然&#xff0c;作为客厅C位的扛把子——电视的娱乐作用深入人心&#xff0c;但是&#xff0c;它的涵义和影响力却因我们每个人的具体生活环境而存在着种种差异&#xff0c;而我们的生活环境又受到我们所处的社会及文化环境的影响。 …

原生 HTML/CSS/JS 实现右键菜单和二级菜单

文章来源&#xff1a;www.huhailong.vip 站点 文章源地址&#xff1a;https://www.huhailong.vip/article/1764653112011841538 Demo效果演示地址 先看效果图 {{{width“auto” height“auto”}}} 需要注意的就是边界检测处理&#xff0c;到极端点击底部和右侧时如果不做处理会…

【网络爬虫】(2) requests模块,案例:网络图片爬取,附Python代码

1. 基本原理 1.1 requests 模块 requests 是 Python 中一个非常流行的 HTTP 客户端库&#xff0c;用于发送所有的 HTTP 请求类型。它基于 urllib&#xff0c;但比 urllib 更易用。 中文文档地址&#xff1a;Requests: 让 HTTP 服务人类 — Requests 2.18.1 文档 &#xff0…

centos 虚拟机 增加硬盘 虚拟机centos磁盘扩容

2 在centos 7 系统中挂载磁盘 2.1 查看磁盘信息 进入centos 7系统中&#xff0c;输入“# df -h”命令&#xff0c;查看磁盘信息。 这里没有写显示新增的磁盘信息。 2.2 对新加的磁盘进行分区操作 2.2.1 查看磁盘容量和分区 2.2.2 创建分区 a. 选择新增的磁盘&#xff08;这…

游戏本续航@控制中心的省电模式效果如何

文章目录 节能模式长续航模式&#x1f47a;相关工具 节能模式长续航模式&#x1f47a; 蓝天模具Control Center中的模式 根据我的试验,以及软件的提示,可以发现 Power Saving是最省电的,儿Quiet模式并不省电,它会启用独立显卡,只不过风扇的转速不像娱乐模式和性能模式那么积极而…

前端删除列表数据后页码重置逻辑

问题描述 需要调整页码的例子&#xff1a; 列表一共有10页数据&#xff0c;用户把第10页数据全部删除后&#xff0c;需要把数据重置成上一页&#xff0c;也就是第9页 不用调整页码的例子&#xff1a; 列表一共有1页数据&#xff0c;用户把本页数据全部删除后&#xff0c;页码…

代码随想录day30(2)回溯:组合(leetcode77)

题目要求&#xff1a;给定两个整数 n 和 k&#xff0c;返回 1 ... n 中所有可能的 k 个数的组合。 思路&#xff1a;首先定义两个变量&#xff0c;一个存放符合条件的单一结果&#xff0c;另一个存放符合条件结果的集合&#xff0c;for循环用来横向遍历&#xff0c;递归用来纵…

Mac电脑虚拟显示器:BetterDisplay Pro for Mac v2.0.11激活版

BetterDisplay Pro是一款由waydabber开发的Mac平台上的显示器校准软件&#xff0c;可以帮助用户调整显示器的颜色和亮度&#xff0c;以获得更加真实、清晰和舒适的视觉体验。 软件下载&#xff1a;BetterDisplay Pro for Mac v2.0.11激活版 以下是BetterDisplay Pro的主要特点&…

8.软件工程

整个章节偏向于记忆、背诵&#xff1b; 主要议题&#xff1a; 软件体系&#xff1a;3层&#xff1b; UML重点&#xff0c;重点记3要素中的关系、图&#xff1b; 1.软件体系结构 分层 优点&#xff1a;利于软件的重复利用&#xff1b; 缺点&#xff1a;以什么方式分层&#…

2024 Python3.10 系统入门+进阶(三):Python变量类型和运算符

目录 一、Python变量的定义和使用二、Python整数类型&#xff08;int&#xff09;详解三、Python小数/浮点数&#xff08;float&#xff09;类型详解四、Python复数类型(complex)详解---了解五、Python字符串详解(包含长字符串和原始字符串)5.1 处理字符串中的引号5.2 字符串的…

【Linux系统】冯诺依曼与操作系统

什么是冯诺依曼体系结构&#xff1f; 如图即为冯诺依曼大致的体系结构图&#xff0c; 我们知道这些都是由我们的计算机硬件组成 输入设备&#xff1a;键盘&#xff0c; 鼠标&#xff0c; 摄像头&#xff0c; 话筒&#xff0c; 磁盘&#xff0c; 网卡... 输出设备&#xff1a…

[HGAME 2023 week2]Designer

[HGAME 2023 week2]Designer 考点&#xff1a;XSS跨站脚本攻击&#xff0c;模板注入 代码审计 function auth(req, res, next) {const token req.headers["authorization"]if (!token) {return res.redirect("/")}try {const decoded jwt.verify(token,…

你在测试金字塔的哪一层(下)

​在《你在测试金字塔的哪一层&#xff08;上&#xff09;》中介绍了自动化测试的重要性以及测试金字塔。测试金字塔分为单元测试、服务测试、UI测试&#xff0c;它们分别是什么呢&#xff1f;本期文章让我们一起详细看看测试金字塔的不同层次。 一、单元测试 单元测试是指对程…

蓝桥杯练习07小兔子爬楼梯

小兔子爬楼梯 介绍 小兔子想去月球上旅行&#xff0c;假设小兔子拥有一个阶梯子&#xff0c;当你爬完层就可以到达月球&#xff0c;小兔子每次可以跳1或者2个台阶&#xff0c;小兔子有多少种跳法可以到达月球呢&#xff1f; 给定n是一个正整数&#xff0c;代表梯子的阶数&…

apisix创建https

总结了下apisix 使用https 的问题和方法 1、apisix 默认https 端口是9443 2、apisix 需要上传证书后才可以使用https 否二curl测试会报错 SSL routines:CONNECT_CR_SRVR_HELLO 3、apisix 上传证书方法 我是使用的自签名证书&#xff0c;注意自签名证书的Common Name 要写你…

【教程】高效数据加密混淆方法及实现简介

背景 在需要对数据进行传输或者表达时&#xff0c;通常要求数据加密的安全级别不高&#xff0c;但希望加解密时间复杂度尽可能低。这时使用传统的对称加密&#xff08;如3DES、AES&#xff09;或非对称加密&#xff08;如RSA、ECC&#xff09;显然不太适合。因为加密的安全级别…

基于深度学习的海洋鱼类识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ............................................................ % 对测试集进行分类预测 [Pr…

深入理解 TreeMap

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇 好几年前&#xff0c;应朋友之邀&#xff0c;为其工厂的厨余垃圾处理设备研发一套用于对现场的生产及维护进行远程查看、管理和质量监控的厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件系统。 因为…