2.15 反初始化
4 分钟阅读
原文链接: https://docs.swift.org/latest/documentation/the-swift-programming-language/deinitialization/
2.15 反初始化
释放需要自定义清理的资源。
反初始化器在类实例被释放之前立即调用。反初始化器用 deinit 关键字书写,就像构造器用 init 关键字书写一样。反初始化器只对类类型可用。
反初始化如何工作
当实例不再需要时,Swift 会自动释放它们以腾出资源。Swift 通过自动引用计数(ARC)管理实例的内存,详见自动引用计数。通常,实例被释放时你不需要手动做清理工作。不过,当你处理自己创建的资源时,可能需要自己做一些额外的清理。例如,如果你创建了一个自定义类来打开文件并写入数据,可能需要在类实例被释放之前关闭该文件。
类的定义最多只能有一个反初始化器。反初始化器不接受任何参数,书写时不带圆括号:
| |
反初始化器会在实例释放之前自动调用,你无权自己调用它。父类的反初始化器会被子类继承,并且在子类反初始化器实现结束时自动调用父类的反初始化器。即使子类没有提供自己的反初始化器,父类的反初始化器也总会被调用。
由于实例要等到它的反初始化器被调用之后才会被释放,反初始化器可以访问调用它的那个实例的所有属性,并根据这些属性调整它的行为(例如查出一个需要关闭的文件的名字)。
反初始化器的实际运用
下面是一个反初始化器实际工作的例子。这个例子为一个小游戏定义了两个新类型:Bank 和 Player。Bank 类管理一种虚拟货币,流通中的金币数量永远不会超过 10,000 枚。游戏中只可能有一个 Bank,因此 Bank 被实现为一个带类型属性和方法的类,用来存储和管理它的当前状态:
| |
Bank 用它的 coinsInBank 属性记录当前持有的金币数量,还提供 distribute(coins:) 和 receive(coins:) 两个方法来处理金币的发放与回收。
distribute(coins:) 方法在发放之前先检查银行中的金币是否足够。如果不够,Bank 就返回比请求数量更少的数字(银行里没有金币时返回零)。它返回一个整数值,表示实际给出的金币数量。
receive(coins:) 方法则只是把收到的金币数量加回银行的储备中。
Player 类描述游戏中的一名玩家。每名玩家在任何时刻钱袋里都存有一定数量的金币,这由玩家的 coinsInPurse 属性表示:
| |
每个 Player 实例在初始化时都会从银行领取指定数量的金币作为启动资金,不过如果银行里的金币不足,Player 实例可能领到比这个数量更少的金币。
Player 类定义了 win(coins:) 方法,从银行取出一定数量的金币并加入玩家的钱袋。Player 类还实现了一个反初始化器,它会在 Player 实例被释放之前调用。这里反初始化器只是把玩家的所有金币还给银行:
| |
这里创建了一个新的 Player 实例,如果银行里有金币就请求 100 枚。这个 Player 实例存放在一个可选 Player 变量 playerOne 中。之所以使用可选变量,是因为玩家可以在任何时刻离开游戏,可选类型让你能够跟踪当前游戏中是否还有玩家。
由于 playerOne 是可选值,访问它的 coinsInPurse 属性来打印初始金币数量时,以及调用它的 win(coins:) 方法时,都要用感叹号(!)限定:
| |
这里玩家赢了 2,000 枚金币,钱袋里现在有 2,100 枚金币,银行则只剩下 7,900 枚。
| |
玩家现在已经离开游戏,这通过把可选变量 playerOne 设为 nil 来表示,意思是"没有 Player 实例"。此时 playerOne 变量对 Player 实例的引用被断开,不再有其他属性或变量引用这个 Player 实例,因此它被释放以腾出内存。就在释放之前,它的反初始化器被自动调用,把金币还给了银行。