Swift 开发教程系列 - 第11章:内存管理和 ARC(Automatic Reference Counting)
在 Swift 中,内存管理由 ARC(自动引用计数)机制自动处理。ARC 通过追踪和管理对象的引用计数来确保分配的内存得到有效释放。尽管 ARC 在大多数情况下能够高效地管理内存,但理解其工作原理仍然十分重要,因为不当的引用会导致内存泄漏或循环引用。本章将介绍 ARC 的基本原理、强引用和弱引用的使用、循环引用的识别和解决方法。
11.1 ARC 基础
ARC 主要用于引用类型(即类)的内存管理。每个类实例在分配时,ARC 会分配一块内存用于存储该实例的所有属性和方法。当一个实例的引用计数变为零时,ARC 自动释放该实例的内存。
示例代码
class Person {let name: Stringinit(name: String) {self.name = nameprint("\(name) is initialized")}deinit {print("\(name) is being deinitialized")}
}var person1: Person? = Person(name: "Alice")
person1 = nil // 当 person1 被赋值为 nil 时,ARC 会释放该内存
在上例中,当 person1 被设置为 nil 后,Person 实例的引用计数变为零,ARC 自动释放该对象并调用 deinit 方法。
11.2 强引用
在 Swift 中,默认情况下,所有的引用都是强引用(strong reference),意味着对象的引用计数会增加。当多个强引用指向同一个对象时,该对象的引用计数会随着引用的增加而增加,只有在所有引用都被移除后,引用计数才会为零,ARC 才会释放对象。
示例代码
class Car {let model: Stringinit(model: String) {self.model = model}
}var car1: Car? = Car(model: "Tesla")
var car2 = car1 // car1 和 car2 都指向同一个 Car 实例
car1 = nil
// car2 仍然持有该实例,因此实例不会被释放
在上例中,即使 car1 被设置为 nil,car2 仍然持有对 Car 实例的强引用,因此该实例不会被释放。
11.3 弱引用和无主引用
为了解决循环引用问题,Swift 提供了 weak(弱引用)和 unowned(无主引用)两种解决方案。
- 弱引用(weak):适用于可能在生命周期中变为 nil 的对象。弱引用不会增加引用计数,因此当没有其他强引用时,对象会被释放。
- 无主引用(unowned):适用于生命周期中不会变为 nil 的对象。无主引用不会增加引用计数,但对象被释放后,如果仍然访问无主引用,会导致程序崩溃。
示例代码
class Owner {let name: Stringvar pet: Pet?init(name: String) {self.name = name}deinit {print("\(name) is being deinitialized")}
}class Pet {let name: Stringweak var owner: Owner? // 使用 weak 解决循环引用init(name: String) {self.name = name}deinit {print("\(name) is being deinitialized")}
}var alice: Owner? = Owner(name: "Alice")
var fluffy: Pet? = Pet(name: "Fluffy")
alice?.pet = fluffy
fluffy?.owner = alicealice = nil // "Alice is being deinitialized"
fluffy = nil // "Fluffy is being deinitialized"
在上例中,Owner 和 Pet 类存在循环引用。通过将 owner 属性声明为弱引用,解决了循环引用问题,使 Owner 和 Pet 可以正确释放。
11.4 闭包和循环引用
闭包在捕获对象时会创建强引用,可能导致循环引用。为了解决这个问题,可以在闭包中使用捕获列表(capture list)指定弱引用或无主引用。
示例代码
class HTMLElement {let name: Stringlet text: String?lazy var asHTML: () -> String = { [weak self] inguard let self = self else { return "" }return "<\(self.name)>\(self.text ?? "")</\(self.name)>"}init(name: String, text: String? = nil) {self.name = nameself.text = text}deinit {print("\(name) is being deinitialized")}
}var paragraph: HTMLElement? = HTMLElement(name: "p", text: "Hello, world!")
print(paragraph?.asHTML() ?? "")
paragraph = nil // "p is being deinitialized"
在上例中,通过 [weak self] 捕获列表防止闭包对 self 创建强引用,避免了循环引用。
11.5 常见的 ARC 内存管理误区
- 过度使用强引用:所有对象都默认使用强引用,但在合适的地方应使用弱引用以避免循环引用。
- 滥用无主引用:无主引用适用于不会变为 nil 的对象,否则会导致崩溃。
- 闭包导致的循环引用:闭包中对 self 的隐式强引用是循环引用的常见原因,使用捕获列表可以避免此问题。
11.6 ARC 优化实践
-
分析引用关系:在设计类之间的引用关系时,避免循环引用的结构,适当地使用 weak 或 unowned 关键字。
-
善用工具:Xcode 提供了内存图和 Instruments 工具,可以帮助检测内存泄漏和循环引用。
-
定期释放对象:在可能产生强引用的地方(如闭包、异步操作等),确认对象在使用后被正确释放。
通过本章的学习,你掌握了 Swift 中的内存管理基础,包括 ARC 的工作原理、强引用和弱引用的使用、以及如何避免循环引用。合理的内存管理对提高应用性能和稳定性至关重要。下一章将介绍 Swift 的高级特性之一:协议和协议扩展,用于构建更具灵活性和扩展性的代码结构。
相关文章:
Swift 开发教程系列 - 第11章:内存管理和 ARC(Automatic Reference Counting)
在 Swift 中,内存管理由 ARC(自动引用计数)机制自动处理。ARC 通过追踪和管理对象的引用计数来确保分配的内存得到有效释放。尽管 ARC 在大多数情况下能够高效地管理内存,但理解其工作原理仍然十分重要,因为不当的引用…...
C#中 layout的用法
在C#中,layout并不是一个直接用于C#语言本身的关键字或特性。然而,layout在与C#紧密相关的某些上下文中确实有其用途,特别是在涉及用户界面(UI)设计和数据展示时。以下是几个常见的与layout相关的用法场景:…...
【编程概念基础知识】
、编程基础 一、面向对象的三大特性 1、封装: 盒子、零件、按钮 隐藏对象 的内部状态,并且只通过对象的方法来访问数据 想象你有一个小盒子(这个盒子就是一个类),里面装着一些零件(这些零件就是数据&a…...

【React】深入理解 JSX语法
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 深入理解 JSX语法1. JSX 简介2. JSX 的基本语法2.1 基本结构2.2 与普通 JavaScr…...

【Linux】从零开始使用多路转接IO --- 理解EPOLL的 LT水平触发模式 与 ET边缘触发模式
当你偶尔发现语言变得无力时, 不妨安静下来, 让沉默替你发声。 --- 里则林 --- 从零开始认识多路转接 1 EPOLL优缺点2 EPOLL工作模式 1 EPOLL优缺点 poll 的优点(和 select 的缺点对应) 接口使用方便:虽然拆分成了三个函数,…...
QtLua
描述 QtLua 库旨在使用 Lua 脚本语言使 Qt4/Qt5 应用程序可编写脚本。它是 QtScript 模块的替代品。 QtLua 不会为 Qt 生成或使用生成的绑定代码。相反,它提供了有用的 C 包装器类,使 C 和 lua 对象都可以从 lua 和 C 访问。它利用 Qt 元对象系统将 QOb…...
c++-有关计数、双变量累加、半衰、阶乘、变量值互换的基础知识
C是一种非常强大和灵活的编程语言,它包含了许多重要的概念和技巧。在本文中,我们将重点讨论五个主题:计数、双变量累加、半衰、阶乘和变量值的互换。我们将介绍这些概念的定义、用法、题目、答案和解释,以帮助读者更好地理解和运用…...

MyBatis3-获取参数值的方式、查询功能及特殊SQL执行
目录 准备工作 获取参数值的方式(重点) 查询功能 查询一个实体类对象 查询一个list集合 查询单个数据 查询一条数据为map集合 查询多条数据为map集合 特殊SQL执行 模糊查询 批量删除 动态设置表名 添加功能获取自增的主键 准备工作 模块My…...

web——[SUCTF 2019]EasySQL1——堆叠注入
这个题主要是讲述了堆叠注入的用法,来复现一下 什么是堆叠注入 堆叠注入:将多条SQL语句放在一起,并用分号;隔开。 1.查看数据库的名称 查看数据库名称 1;show databases; 发现有名称为ctftraining的数据库 2.对表进行查询 1;show tabl…...

【Ubuntu学习】Ubuntu无法使用vim命令编辑
问题 在VMware首次安装Ubuntu,使用vi指令对文件进行编辑,按i键后无法更改文件内容。 原因 由于Ubuntu中预装的是vim-tiny,平时开发中需要使用vim-full。 解决方案 卸载预装vim sudo apt-get remove vim-common安装vim-full sudo apt-get …...

UniAPP u-popup 禁止背景滑动
增加class .NoScroll {overflow: hidden;position: fixed; }在外层div上增加该class判断条件...
F5全新报告揭示AI时代API安全面临严峻挑战
F5 《2024年应用策略现状报告:API安全》揭示了 API 保护中的漏洞以及对全面安全措施的迫切需求 西雅图,2024年11月11日 – F5(NASDAQ: FFIV)日前发布《2024年应用策略现状报告:API 安全》(以下简称为“报告”),揭示了跨行业API安全面临的严峻现状。该报告强调了企业API保护方面…...

使用C语言进行信号处理:从理论到实践的全面指南
1. 引言 在现代操作系统中,信号是一种进程间通信机制,它允许操作系统或其他进程向一个进程发送消息。信号可以用来通知进程发生了一些重要事件,如用户请求终止进程、硬件异常、定时器超时等。掌握信号处理技术对于开发健壮、高效的系统程序至…...

什么是工单管理系统?全面认识指南
在现代企业中,客户服务和支持是业务成功的关键因素之一。为了有效地管理客户请求和问题,许多公司采用了工单管理系统。本文将深入探讨工单管理系统的定义、功能、优势。 一、工单管理系统的定义 工单管理系统是一种软件工具,旨在帮助企业管…...

集群化消息服务解决方案
目录 集群化消息服务解决方案项目概述架构图使用说明服务端通过API接口推送消息给客户端调用方式 请求参数返回参数 客户端推送消息连接websocket或发送消息 接收消息项目地址作者信息 集群化消息服务解决方案 项目概述 集群化消息服务解决方案是一种用于处理大量消息的高可用…...

python数据结构操作与可视化的应用
Python具有丰富的数据结构操作和可视化库,可以进行各种数据结构的创建、编辑和分析,并将结果可视化。以下是几个常见的Python数据结构操作和可视化的应用示例: 1. 列表(List)操作和可视化: - 创建列表&a…...
【基于轻量型架构的WEB开发】课程 作业4 AOP
一. 单选题(共7题,38.5分) 1 (单选题)下列选项中,用于通知/增强处理的是( )。 A. Joinpoint B. Pointcut C. Aspect D. Advice 正确答案:D 答案解析:在面向切面编程ÿ…...

跨境独立站新手,如何用DuoPlus云手机破局海外社媒引流?
独立站作为电商领域的一个重要组成部分,其发展在最近几年里确实令人瞩目,对于想要进入跨境赛道的新手卖家来说,手上握着有优势的货源,建立小型的DTC独立站确实会比入驻第三方平台具有更大的灵活性。本文将给跨境卖家们总结独立站和…...

【Android、IOS、Flutter、鸿蒙、ReactNative 】标题栏
Android 标题栏 参考 Android Studio版本 配置gradle镜像 阿里云 Android使用 android:theme 显示标题栏 添加依赖 dependencies {implementation("androidx.appcompat:appcompat:1.6.1")implementation("com.google.android.material:material:1.9.0")…...

信息安全工程师(83)Windows操作系统安全分析与防护
一、Windows操作系统安全分析 系统漏洞: Windows操作系统由于其复杂性和广泛使用,可能存在一些已知或未知的漏洞。这些漏洞可能会被黑客利用,进行恶意攻击。微软会定期发布系统更新和补丁,以修复这些漏洞,提高系统的安…...

Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...