🎬 HoRain 云小助手:个人主页
⛺️生活的理想,就是为了理想的生活!
⛳️ 推荐
前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。
目录
⛳️ 推荐
一、析构过程的基本原理
二、析构函数的定义与使用
三、析构过程与ARC的关系
四、析构函数的典型应用场景
五、最佳实践与注意事项
六、完整示例:银行与玩家系统
Swift中的**析构过程(Deinitialization)**是对象生命周期的最后阶段,当类的实例被释放时,系统会自动调用析构函数deinit执行必要的清理工作,这是Swift内存管理机制的重要组成部分。
一、析构过程的基本原理
核心机制:
- 析构过程是对象释放前的自动清理阶段,由Swift运行时系统自动触发
- 仅适用于类(class)类型,不适用于结构体(struct)和枚举(enum)
- 与构造过程相反:构造器
init在对象创建时调用,而析构器deinit在对象销毁前调用
触发条件:
- 当类实例的引用计数减为0时触发(通过ARC机制管理)
- 常见触发场景:
- 将实例变量设置为
nil - 实例离开作用域(如函数执行完毕)
- 移除对实例的所有强引用
- 将实例变量设置为
二、析构函数的定义与使用
基本语法:
class MyClass { deinit { // 清理代码 print("对象被释放") } }- 无参数、无返回值、不能重载
- 不能手动调用,由系统自动触发
- 每个类最多只能有一个析构函数
执行顺序:
- 在对象生命周期结束时自动调用
- 先创建的对象先被析构(逆序执行)
- 子类析构时会自动调用父类析构函数,即使子类没有提供自己的析构器
三、析构过程与ARC的关系
Swift通过**自动引用计数(ARC)**管理内存,析构过程是ARC机制的关键环节:
ARC工作流程:
- 当对象被创建时,引用计数初始化为1
- 每增加一个强引用,引用计数+1
- 每移除一个强引用,引用计数-1
- 当引用计数减为0时,触发析构过程
内存释放流程:
引用计数减为0 → 调用deinit → 执行清理工作 → 释放内存常见陷阱:
- 强引用循环:两个对象互相持有对方的强引用,导致引用计数无法减为0,无法触发析构
- 解决方案:使用
weak(弱引用)或unowned(无主引用)打破循环引用
四、析构函数的典型应用场景
资源清理:
- 关闭文件句柄:确保文件操作完成后正确关闭
- 断开网络连接:释放网络资源
- 关闭数据库连接:避免资源泄漏
class FileManager { let filename: String init(filename: String) { self.filename = filename print("打开文件: \(filename)") } deinit { print("关闭并释放文件: \(filename)") } }移除观察者:
- 通知中心:从
NotificationCenter中移除观察者 - 委托模式:将委托对象设为
nil或从其他对象的委托列表中移除
class MyObserver { init() { NotificationCenter.default.addObserver(self, selector: #selector(handleEvent), name: .someEvent, object: nil) } deinit { NotificationCenter.default.removeObserver(self) print("Observer deinitialized") } }- 通知中心:从
取消异步任务:
- 定时器:使
Timer失效 - 网络请求:取消
URLSession任务 - Combine订阅:取消
AnyCancellable
class TimerHandler { var timer: Timer? init() { timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in print("Tick") } } deinit { timer?.invalidate() print("Timer invalidated") } }- 定时器:使
调试与追踪:
- 打印析构信息,验证对象是否被正确释放
- 检查是否存在内存泄漏(如循环引用)
deinit { print("ViewController has been released!") }
五、最佳实践与注意事项
避免循环引用:
- 使用
weak或unowned修饰符打破引用循环 - 特别注意闭包中捕获
self可能导致的循环引用
- 使用
析构函数中的限制:
- 不要在析构函数中调用
self,可能导致循环引用或未定义行为 - 析构函数中不能抛出错误
- 析构函数不能有参数
- 不要在析构函数中调用
资源管理原则:
- 及时释放:确保在析构函数中释放所有持有的资源
- 避免重复释放:检查资源是否已被释放
- 保持简洁:析构函数应专注于资源清理,避免复杂逻辑
调试技巧:
- 使用Xcode的内存调试工具检测循环引用
- 在析构函数中添加日志输出,验证对象释放时机
- 使用
weak变量测试对象是否被正确释放
六、完整示例:银行与玩家系统
class Bank { static var coinsInBank = 10_000 static func distribute(coins numberOfCoinsRequested: Int) -> Int { let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank) coinsInBank -= numberOfCoinsToVend return numberOfCoinsToVend } static func receive(coins: Int) { coinsInBank += coins } } class Player { var coinsInPurse: Int init(coins: Int) { coinsInPurse = Bank.distribute(coins: coins) print("A new player has joined the game with \(coinsInPurse) coins") } func win(coins: Int) { coinsInPurse += Bank.distribute(coins: coins) print("Player won \(coins) coins & now has \(coinsInPurse) coins") } deinit { Bank.receive(coins: coinsInPurse) print("Player has left the game. Bank now has \(Bank.coinsInBank) coins") } } // 使用示例 var player: Player? = Player(coins: 100) player?.win(coins: 2000) player = nil // 触发析构过程在这个示例中,当玩家离开游戏(player = nil)时,系统会自动调用Player类的析构函数,将玩家的硬币归还给银行,确保资源得到正确清理。
掌握Swift的析构过程对于编写高效、稳定的iOS应用至关重要,它能帮助开发者避免内存泄漏、资源浪费等问题,确保应用在各种场景下都能正确管理资源。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙