当前位置: 首页 > news >正文

【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数(四)

目录

ARC规则

规则

对象型变量不能作为C语言结构体的成员

显式转换id和void*

属性

数组


ARC规则

规则

在ARC有效的情况下编译源代码必须遵守一定的规则:

主要解释一下最后两条

对象型变量不能作为C语言结构体的成员

要把对象型变量加入到结构体成员中时,可强制转换为void*或是附加前面所述的__unsafe_unretained修饰符。

显式转换id和void*

ARC无效时,像以下代码这样将id变量强制转换void*变量并不会出问题。

id obj = [[NSObejct alloc] init];
void *p = obj;

更进一步,将该void*变量赋值给id变量中,调用其实例方法,运行时也不会有问题

id o = p;
[o release];

但是在ARC有效时这便会引起编译错误。

id型或对象型变量赋值给void*或者逆向赋值时都需要进行特定的转换。如果只想单纯地赋值,则可以使用"__bridge转换"。

id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
id o = (__bridge id)p;

像这样,通过"__bridge转换",id和void*就能互相转换。

但是转换为void* 的__bridge转换,其安全性与赋值给__unsafe_unretained修饰符相近,甚至会更低。如果管理时不注意赋值对象的所有者,就会因悬垂指针而导致程序崩溃。

__bridge转换中还有另外两种转换,分别是“__bridge_retained转换”和"__bridge_transfer转换"

id obj = [[NSObject alloc] init];
void *p = (__bridge_retained void *)obj;

__bridge_retained转换可使要转换赋值的变量也持有所赋值的对象。下面来看看ARC无效时的源代码是如何编写的

id obj = [[NSObject alloc] init];
void *p = obj;
[(id)p retain];

__bridge_retained转换变为了retain。变量obj和变量p同时持有对象。再来看几个其他的例子。

void *p = 0;
{id obj = [[NSObject alloc] init];p = (__bridge_retained void *)obj;
}
NSLog(@"class=%@", [(__bridge id)p class]);

变量作用域结束时,虽然随着持有强引用的变量obj失效,对象随之释放,但由于__bridge_retained转换使变量p看上去处于持有该对象的状态,因此该对象不会被废弃。下面我们比较一下ARC无效时的代码

void *p = 0;
​
{id obj = [[NSObject alloc] init];//[obj retainCount] -> 1p = [obj retain];//[obj retainCount] -> 2[obj release];//[obj retainCount] ->1
}
//[(id)p retainCount] -> 1
//即 [obj retainCount] -> 1
//对象仍存在
NSLog(@"class=%@", [(__bridge id)p class]);

__bridge_transfer转换提供与此相反的动作,被转换的变量所持有的对象在该变量被赋值给转换目标变量后随之释放。

id obj = (__bridge_transfer id)p;

该源代码在ARC无效时这样表述:

id obj = (id)p;
[obj retain];
[(id)p release];

__bridge_retained转换与retain类似,__bridge_transfer转换与release相似。在给id obj赋值时retain即相当于__strong修饰符的变量。

如果使用以上两种转换,那么不使用id型或对象型变量也可以生成、持有以及释放对象。虽然可以这样做,但是在ARC中不推荐这种方法

void *p = (__bridge_retained void *)[[NSObject alloc] init];
NSLog(@"class=%@", [(__bridge id)p class]);
(void)(__bridge_transfer id)p;

该源代码与ARC无效时的下列源代码相同

//ARC无效
id p = [[NSObject alloc] init];
NSLog(@"class=%@", [p class]);
[p release];

这些转换多用于OC对象与CF对象之间的相互变换中。

OC对象和CF对象的区别很小,不同之处仅仅只在于生成对象的框架不同。可以使用免费桥来实现二者之间的转换("Toll—Free Bridge",这种转换不用使用额外的CPU资源)。

以下函数即Toll—Free Bridge转换的函数,可用于OC对象和CF对象之间的相互变换,即Toll—Free Bridge转换。

属性

当ARC有效时,OC类的属性也会发生变化。

以上各种属性赋值给指定的属性中就相当于赋值给附加各属性对应的所有权修饰符的变量中。只有copy属性不是简单的赋值,它赋值的是通过NSCopying接口的copyWithZone:方法复制赋值源所生成的对象。

并且,在声明类成员变量时,如果同属性声明中的属性不一致则会引起编译错误。比如下面这种情况。

id obj;
@property (nonatomic, weak)id obj;

在声明id型obj成员变量时,定义属性声明为weak,编译器报错。

此时,需要在成员变量的声明中附加__weak修饰符或者使用strong属性来替代weak属性。

数组

将变量作为静态数组使用时,附有__strong,__weak,__autoreleasing修饰符的数组可以在初始化时初始化为nil。

而对于动态数组,NSMutableArray、NSMutableDicitionary、MSMutableSet等容器会恰当地持有追加的对象并为我们管理这些对象。

像这样使用容器虽然更为合适,但在C语言的动态数组中也可以使用附有__strong修饰符的变量,但是要遵守一些事项:

声明动态数组用指针

id __strong *array = nil;

id *类型默认为"id __autoreleasing*类型",所以要显式指定修饰符__strong。并且,附有__strong只保证id型变量被初始化为nil,并不保证附有__strong修饰符的id指针型变量被初始化为nil。

使用类名时如下记述:

NSObject * __strong *array = nil;

其次使用calloc函数确保想分配的附有__strong修饰符变量的容量占有的内存块。

array = (id __strong *)calloc(entries, sizeof(id));

该源代码分配了entries个所需的内存块。由于使用附有__strong修饰符的变量前必须先将其初始化为nil,所以这里使用使分配区域初始化为0的calloc函数来分配内存。不使用calloc函数,在用malloc函数分配内存后可用memset等函数将内存填充为0。

但是,像下面的源代码这样,将nil代入到malloc函数所分配的数组各元素中来初始化是非常危险的。

array = (id __strong *)malloc(sizeof(id) * entries);
for (NSUInteger i = 0; i < entries; ++i)array[i] = nil;

这是因为由malloc函数分配的内存区域没有被初始化为0,因此nil会被赋值给附有__strong修饰符的并被赋值了随机地址的变量中,从而释放一个不存在的对象。在分配内存时推荐使用calloc函数。

像这样,通过calloc函数分配的动态数组就能完全像静态数组一样使用。

array[0] = [[NSObject alloc]];

但是,在动态数组中操作附有__strong修饰符的变量与静态数组有很大差异,需要自己释放所有的元素。在只是简单地使用free函数废弃了数组用内存块的情况下,数组各元素所赋值的对象不能被再次释放,从而引起内存泄漏。这是因为在静态数组中,编译器能根据变量作用域自动插入释放赋值对象的代码,而在动态数组中,编译器不能确定数组的生存周期,所以无从处理。

使用动态数组时,一定要将nil赋值给所有元素中,使得元素所赋值对象的强引用失效,从而释放那些对象。在此之后,使用free函数废弃内存块。

for (NSUInteger i = 0; i < entries; ++i) array[i] = nil;
free(array);

同初始化的注意事项相反,即使用memset等函数将内存填充为0也不会释放所赋值的对象。这非常危险,只会引起内存泄漏。对于编译器,必须明确地使用赋值给附有__strong修饰符变量的源代码。所以请注意,必须将nil赋值给所有数组元素。

并且,memcpy和realloc函数也会有危险,因为数组元素所赋值的对象有可能被保留在内存中或是重复被废弃,所以也禁止使用。

相关文章:

【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数(四)

目录 ARC规则 规则 对象型变量不能作为C语言结构体的成员 显式转换id和void* 属性 数组 ARC规则 规则 在ARC有效的情况下编译源代码必须遵守一定的规则&#xff1a; 主要解释一下最后两条 对象型变量不能作为C语言结构体的成员 要把对象型变量加入到结构体成员中时&a…...

嵌入式软考学习笔记(1)超详细!!!

目录 第一章计算机系统基础知识 1、逻辑运算 2、数的表示 3、总线系统 5、流水线 6、存储器 7、可靠性、校验码 第一章计算机系统基础知识 1、逻辑运算 与&#xff1a;有0则0&#xff0c;全1才1 或&#xff1a;有1则1&#xff0c;全0才0 异或&#xff1a;相同为0…...

【数据分享】2013-2023年我国省市县三级的逐年CO数据(免费获取\excel\shp格式)

空气质量数据是在我们日常研究中经常使用的数据&#xff01;之前我们给大家分享了2000-2023年的省市县三级的逐年PM2.5数据、2000-2023年的省市县三级的逐年PM10数据、2013-2023年的省市县三级的逐年SO2数据、2000-2023年省市县三级的逐年O3数据和2008-2023年我国省市县三级的逐…...

C# 探险之旅:第十六节 - 整数类型:与八位数字精灵的奇幻舞会

嘿&#xff0c;勇敢的探险家们&#xff01;欢迎再次踏上C#编程的奇幻之旅。今天&#xff0c;我们将进入一个充满魔法与数字的世界——整数类型的王国。想象一下&#xff0c;你站在一个华丽的舞池中&#xff0c;周围是八位身着华丽舞裙&#xff08;其实是二进制位啦&#xff09;…...

Cleo文件传输软件存在任意文件读取漏洞(CVE-2024-50623)

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…...

Java 小抄|解析 JSON 并提取特定层级数据

文章目录 前言环境准备依赖库 示例代码JSON 数据Java 类定义解析 JSON 数据代码解释 结论 前言 在日常开发中&#xff0c;我们经常需要从 JSON 数据中提取特定的信息。本文将介绍如何使用 Java 和 Gson 库解析 JSON 数据&#xff0c;并通过流式处理提取特定层级的数据。我们将…...

活动报名:Voice Agent 开发者分享会丨RTE Meetup

引入 voice agent 的口语学习应用 Speak 估值已达 10 亿美元 Voice Agent 开发者分享会 一同探索语音驱动的下一代人机交互界面&#xff0c;一场 voice agent builder 的小规模深度交流会。 RTE Meetup 迎来第六期&#xff01;12 月 15 日&#xff08;周日&#xff09;上午&…...

DOA估计算法——ESPRIT算法

1 简介 ESPRIT&#xff08;Estimation of Signal Parameters via Rotational Invariance Techniques&#xff09;最早是由Roy等人于1986年提出&#xff0c;是一种广泛应用于高分辨率方向到达&#xff08;DOA&#xff09;估计和频率估计的子空间方法。其核心思想基于信号子空间的…...

CEF 数据加密与网络安全

随着网络攻击的日益猖獗&#xff0c;确保应用的安全性已经成为开发者的首要任务。特别是在现代Web应用中&#xff0c;如何确保数据的加密存储、网络通信的安全性以及有效的认证机制成为至关重要的问题。对于基于 Chromium Embedded Framework (CEF) 的应用&#xff0c;开发者必…...

go build command

文章目录 1.简介2.格式3.选项4.示例5.小结参考文献 1.简介 go build 是 Go 语言工具链中的一个命令&#xff0c;它用于编译 Go 源代码并生成可执行文件。 2.格式 go build [-o output] [build flags] [packages]可选的 -o 选项强制 build 将生成的可执行文件或对象写入指定的…...

理解音频采样率和transformer模型:给Python小白的简单解释

理解音频采样率和transformer模型&#xff1a;给Python小白的简单解释 引言什么是采样率&#xff1f;举个例子有趣的现象Python小实验总结 引言 大家好&#xff01;今天我们来聊一个有趣的话题&#xff1a;音频采样率和AI模型。不要被这些专业术语吓到&#xff0c;我会用最简单…...

【RL Latest Tech】安全强化学习(Safe RL):理论、方法与应用

&#x1f4e2;本篇文章是博主强化学习&#xff08;RL&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…...

大模型qiming面试内容整理-系统设计与架构

在大模型和机器学习相关岗位的面试中,系统设计与架构的考察通常会涉及如何设计一个可扩展、可靠且高效的机器学习系统,特别是在面对大规模数据和复杂模型时。这一部分的考察不仅测试候选人对机器学习和深度学习的理解,还会评估其如何设计实际生产环境中的系统来满足需求。以…...

Mac/Windows端长期破解myBase8方法(无需安装火绒)

提醒 不管哪个端&#xff0c;都需要先退出myBase。 Mac 进入用户根目录/Users/c0ny100&#xff0c;即下边是Macintosh HD > 用户 > [你的用户名]这个界面然后按ShiftCommond.&#xff0c;显示隐藏文件。找到.Mybase8.ini文件 打开.Mybase8.ini文件&#xff0c;删除Fir…...

firewall

firewall 如果系统使用 firewalld 作为防火墙管理工具&#xff0c;可以使用以下命令&#xff1a; 查看防火墙是否运行&#xff1a; systemctl status firewalld查看防火墙的状态&#xff08;简洁输出&#xff09;&#xff1a; firewall-cmd --state输出示例&#xff1a; r…...

XSS(跨站攻击)

XSS漏洞&#xff08;跨站脚本&#xff09; 1.XSS 漏洞简介 ​ XSS又叫CSS&#xff08;Cross Site Script&#xff09;跨站脚本攻击是指恶意攻击者往Web页面里插入恶意Script代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入其中Web里面的Script代码会被执行&#xff0c;从…...

Tomcat添加各种响应头 X-Download-Options、Permissions-Policy等

AI越来越火了,我们想要不被淘汰就得主动拥抱。推荐一个人工智能学习网站,通俗易懂,风趣幽默,最重要的屌图甚多,忍不住分享一下给大家。点击跳转到网站。 最近部署的项目被绿盟扫出来很多web漏洞,其中tomcat响应占了很大一部分。下面我们整理一下如何处理。 首先说说常见…...

搭建Tomcat(一)---SocketServerSocket

目录 引入1 引入2--socket 流程 Socket&#xff08;应用程序之间的通讯保障&#xff09; 网卡(计算机之间的通讯保障) 端口 端口号 实例 client端 解析 server端 解析 相关方法 问题1&#xff1a;ServerSocket和Socket有什么关系&#xff1f; ServerSocket Soc…...

ubuntu 使用 Times New Roman 字体在 Matplotlib 中绘图并调整字体大小

ubuntu 使用 Times New Roman 字体在 Matplotlib 中绘图并调整字体大小 文章目录 ubuntu 使用 Times New Roman 字体在 Matplotlib 中绘图并调整字体大小1. 安装 Times New Roman 字体验证字体是否安装成功 2. 在 Matplotlib 中加载 Times New Roman 字体3. 在 Matplotlib 中使…...

openGauss开源数据库实战二十三

文章目录 任务二十三 openGauss 参数管理任务目标实施步骤一、启动参数文件及参数类型1.参数值修改后必须重新启动数据库的参数2.参数值修改后只需要reload操作的参数 二、设置数据库级参数三、设置用户级参数四、设置会话级参数五、将参数设置为默认值 任务二十三 openGauss 参…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

python打卡第47天

昨天代码中注意力热图的部分顺移至今天 知识点回顾&#xff1a; 热力图 作业&#xff1a;对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图&#xff0c;展示模…...