swift 学习- 17 -- 析构器
// 析构器 只适用与 类类型, 当一个类的实例被释放之前, 析构器会被立即调用, 析构器用关键字 deinit 来标示, 类似于构造器要用 init 来标示
// 析构过程原理
// Swift 会自动释放不再需要的实例以释放资源, 如 自动引入计数 章节中所描述, Swift 通过自动引用计数 (ARC) 处理实例的不存管理. 通常当你的实例被释放是不需要 手动去清理, 但是, 当使用自己的资源时, 你可能需要进行一些额外的清理, 例如, 如果创建了一个自定义的类来打开文件, 并写入一些数据, 你可能需要在类实例被释放之前手动去关闭该文件
// 在类的定义中, 每个类最多只能有一个析构器, 而且析构器不带任何参数
// deinit{
// 执行析构过程
// }
// 析构器是在实例释放发生前被自动调用, 你不能主动调用 析构器, 子类继承了父类的析构器, 并且在子类析构器实现的最后, 父类的析构器 会被自动调用, 即使子类没有提供自己的析构器, 父类的析构器也同样会被调用
// 因为直到实例的 析构器被调用后, 实例才会被释放, 所以析构器可以访问实例的所有属性, 并且可以根据那些属性可以修改它的行为 (比如查找一个需要关闭的文件)
// 析构器实践
// 这是一个析构器实践的例子, 这里定义了两种新类型, 分别是 Bank 和 Player
// Bank 类管理一种虚拟硬币, 确保流通的硬币数量永远不可能超过 10000, 在游戏中有且只能有一个 Bank 存在, 因此 Bank 用类来实现, 并使用类型属性 和 类型方法 来 存储和管理其当前状态
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
}
}
// Bank 使用 coinsInBank 属性来跟踪它当前拥有的硬币数量, Bank 还提供了两个方法, distribute(coins:) 和 receive(coins:) , 分别用来处理硬币的 分发 和 收集
// distribute(coins:) 方法在 Bank 对象分发硬币之前检查是否有足够的硬币, 如果硬币不足, Bank 对象会返回一个比请求时小的数字, (如果不够, 有多少发多少, 没有就发 0), 此方法返回一个整型值, 表示提供硬币的实际数量, receive(coins:) 方法只是将 Bank 实例接收到的硬币数目加回硬币存储中
// Player 类描述了游戏中的一个玩家, 每一个玩家在任意时间都有一定数量的硬币存储在他们的其阿宝中, 这通过玩家的 coinsInPurse 属性来表示
class Player{
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
Bank.receive(coins: coinsInPurse)
}
}
// 每个 Player 实例在初始化的过程中, 都从 Bank 对象获取指定数量的硬币, 如果没有足够的硬币可用, Player 实例可能会收到比指定数量少的 硬币
// Player 类定义了一个 win(coins:) 方法, 该方法从 Bank 对象获取一定数量的硬币, 并把它们添加到玩家的钱包,
// Player 类还实现了一个析构器, 这个析构器在 Player 实例释放前被调用, 在这里, 析构器的作用只是将玩家的所有硬币都返还给 Bank 对象
var playerOne: Player? = Player(coins: 100)
print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
print("There are now \(Bank.coinsInBank) coins left in the bank")
// 创建一个Player实例的时候,会向Bank对象请求 100 个硬币,如果有足够的硬币可用的话。这个Player实例存储在一个名为playerOne的可选类型的变量中。这里使用了一个可选类型的变量,因为玩家可以随时离开游戏,设置为可选使你可以追踪玩家当前是否在游戏中。
// 因为playerOne是可选的,所以访问其coinsInPurse属性来打印钱包中的硬币数量时,使用感叹号(!)来解包:
playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// 输出 "PlayerOne won 2000 coins & now has 2100 coins"
print("The bank now only has \(Bank.coinsInBank) coins left")
// 输出 "The bank now only has 7900 coins left"
// 这里,玩家已经赢得了 2,000 枚硬币,所以玩家的钱包中现在有 2,100 枚硬币,而Bank对象只剩余 7,900 枚硬币。
playerOne = nil
print("PlayerOne has left the game")
// 打印 "PlayerOne has left the game"
print("The bank now has \(Bank.coinsInBank) coins")
// 打印 "The bank now has 10000 coins"
// 玩家现在已经离开了游戏。这通过将可选类型的playerOne变量设置为nil来表示,意味着“没有Player实例”。当这一切发生时,playerOne变量对Player实例的引用被破坏了。没有其它属性或者变量引用Player实例,因此该实例会被释放,以便回收内存。在这之前,该实例的析构器被自动调用,玩家的硬币被返还给银行。
swift 学习- 17 -- 析构器的更多相关文章
- Swift 析构器deinit
析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用.析构器用关键字deinit来标识,类似于构造器用init来标识. 原理: Swift会自动释放不再需要的实例以释放资源.Swift通 ...
- swift学习笔记之-析构过程
//析构过程deist import UIKit /*析构过程(Deinitialization):析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用.析构器用关键字deinit来标示 ...
- Swift构造器(Initializer)与析构器(Deinitializer)
为了初始化结构体和类等类型的实例属性. 默认构造器 struct Fahrenheit { var temperature: Doubleinit(){ temperature = 32.0 } } ...
- Swift中子类必须包含的构造器和析构器
import Foundation /* Swift中子类必须包含的构造器 1.Swift允许在父类构造器前添加required关键字, 用于声明所有子类必须包含该required构造器 (如果没有声 ...
- objective-C学习笔记(五)函数成员:初始化器和析构器
初始化器:init 对象初始化器: -(id)init 可以重载多个. 类型初始化器: +(id)initialize只能有一个. 对象初始化器: 初始化对象实例时,init通常和alloc(手动内存 ...
- swift学习笔记4——扩展、协议
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- swift学习笔记3——类、结构体、枚举
之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...
- Swift中类的初始化器与继承
初始化是类,结构体和枚举类型实例化的准备阶段.这个阶段设置这个实例存储的属性的初始化数值和做一些使用实例之前的准备以及必须要做的其他一些设置工作. 通过定义构造器(initializers)实现这个实 ...
- 【Swift学习】Swift编程之旅---构造方法(十八)
初始化是为了使用某个类.结构体或枚举类型的实例而进行的准备过程.这个过程包括为每个存储的属性设置一个初始值,然后执行新实例所需的任何其他设置或初始化. 初始化是通过定义构造器(Initialize ...
随机推荐
- IL 学习笔记
先上几篇博客链接: 一步步教你读懂NET中IL(图文详解) C#基础之IL 详解.NET IL代码 C# IL DASM 使用 你必须知道的.NET <C# to IL>.<Expe ...
- ES5新增内容
一.数组API实际开发中forEach和map会多一些=>是es6语法中的arrow function举例:(x) => x + 6相当于function(x){return x + 6; ...
- python操作Excel-写/改/读
python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库. xlrd和xlwt这两个库用之前需要安装:cmd -> pip instal ...
- jmeter 压力测试(二) 获取不同格式的当前时间
在jmeter中获取当前时间可以用“time”函数,可以设置不同的格式,如下为几个最常见的例子: 输出看一下: 如此,基本满足了日常的需求,令可以根据自己的时间需求,设置格式.
- 为何invalidate()不可以直接在UI线程中调用&invalidate与postInvalidate
1.android ui操作为什么一定要在主线程中执行? 答:Android UI操作是单线程模型,关于UI更新的相关API(包括invalidate())都是按照单线程设计的,对于多线程运行时不安全 ...
- js 一个对象的属性名是一个变量怎么处理?
1.这种方法的属性(setAttrName)可以是一个变量. var obj = {}; obj[setAttrName] = 'Tom' 2.这样就可以动态的给js对象添加变量属性. var obj ...
- 20165234 《Java程序设计》第七周学习总结
第七周学习总结 教材内容学习 第十一章 JDBC与MySQL数据库 连接数据库: 1. 下载JDBC-MySQL数据库驱动 2. 加载JDBC-MySQL数据库驱动 3. 连接数据库 条件与排序查询: ...
- android checkBox选中与取消
checkView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO ...
- Android 5.0以上Material Design 沉浸式状态栏
偶然在知乎上看到这个问题,Android 5.0 如何实现将布局的内容延伸到状态栏,之前也见过多个应用的这个功能,但是知乎上的答案却没有一个真正实现此功能的一类是把标题栏设置App主题颜色,一类是提取 ...
- codevs 1080 线段树练习(线段树)
题目: 题目描述 Description 一行N个方格,开始每个格子里都有一个整数.现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和:修改的规则是指定某一个格子x ...