【问题标题】:When should I use deinit?我应该什么时候使用 deinit?
【发布时间】:2014-07-24 00:01:14
【问题描述】:

我在阅读 The Swift Programming Language guide 时遇到了一个名为 deinit() 的函数,但我仍然想知道为什么以及何时需要实现它,因为我们真的不需要管理内存。

【问题讨论】:

  • 在 ARC 下的 obj-c 中使用 dealloc 的情况相同。
  • 是 swift 中的 deinit 和 java 中的 finalize() 一样没用,还是 swift 更擅长预测什么时候会被释放?

标签: swift


【解决方案1】:

您不需要实现该方法,但如果您需要在释放对象之前执行一些操作或清理,则可以使用它。

Apple docs 包含一个示例:

struct Bank {
    static var coinsInBank = 10_000
    static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
        numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    static func receiveCoins(coins: Int) {
        coinsInBank += coins
    }
}

class Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.vendCoins(coins)
    }
    func winCoins(coins: Int) {
        coinsInPurse += Bank.vendCoins(coins)
    }
    deinit {
        Bank.receiveCoins(coinsInPurse)
    }
}

因此,每当玩家从游戏中移除时,其硬币都会返还给银行。

【讨论】:

  • 你会如何从游戏中“移除”一个玩家?我有一个汽车课,如果那辆车发生碰撞,它会被送到垃圾场,因此总体汽车数量会下降。我想从汽车人口中删除汽车。我有我的 deinit { Car.population -= 1 } 但不知道如何实际释放和减少人口。
  • 知道为什么 Apple 将 struct Bank 更改为 Bank 类吗?
  • @user523234 因为银行有明确的身份,所以你去哪家银行存钱。银行不仅仅是一个抽象概念(信息的集合),即使拥有完全相同的信息的两家银行也不会是同一家银行。
  • 终止是一回事,但是方法返回或抛出呢; deinit 是在最后一个 obj-ref 超出范围时立即调用,还是我应该一次又一次地使用 defer 来代替,哪里需要这种行为?
【解决方案2】:

在释放类实例之前立即调用deinit(),这在您使用自己的资源时很有帮助。例如,如果您创建一个自定义类来打开一个文件并向其中写入一些数据,您可能需要在释放类实例之前关闭该文件。要记住的最重要的事情是类定义每个类最多可以有一个deinit()

【讨论】:

    【解决方案3】:

    从 iOS9 开始,自动调用 removeObserver。

    【讨论】:

    【解决方案4】:

    如果您的类管理文件句柄或其他资源,您可以在 deinit 中关闭该句柄,以确保在对象被释放后它不会继续存在。

    【讨论】:

      【解决方案5】:

      在释放类实例之前立即调用取消初始化程序。您使用 deinit 关键字编写反初始化器,类似于使用 init 关键字编写初始化器的方式。反初始化器仅适用于类类型。类定义每个类最多可以有一个反初始化器。 deinitializer 不带任何参数,并且不带括号。 我使用 deinit 从应用程序中删除通知的观察者,如下所示。

      deinit {
          NotificationCenter.default.removeObserver(self, name: 
          NSNotification.Name(rawValue: "gotoLogin"), object: nil)
          NotificationCenter.default.removeObserver(self, name: 
          NSNotification.Name(rawValue: "gotoMain"), object: nil)
          NotificationCenter.default.removeObserver(self, name: 
          NSNotification.Name(rawValue: "gotoRegister"), object: 
          nil)
          NotificationCenter.default.removeObserver(self, name: 
          NSNotification.Name(rawValue: "gotoBook"), object: nil)
          NotificationCenter.default.removeObserver(self, name: 
          NSNotification.Name(rawValue: "gotoCurrentMainMenu"), 
          object: nil)
          NotificationCenter.default.removeObserver(self, name: 
          NSNotification.Name(rawValue: "gotoEventMenu"), 
          object: nil)
      }
      

      【讨论】:

      • 你可以这样做,它会释放所有通知 NotificationCenter.default.removeObserver(self)
      【解决方案6】:

      如果您在某个需要按您的节奏释放的对象中创建大量操作,您可以在 deinit 中执行此操作

      【讨论】:

        【解决方案7】:

        “最佳答案”现在应该更像这样

        我无法编辑它

         struct Bank {
        static var coinsInBank = 10000
        static func vendCoins(money numberOfCoinsToVend: Int) -> Int {
            let CoinsToVend = min(numberOfCoinsToVend, coinsInBank)
            coinsInBank -= CoinsToVend
            return CoinsToVend
        }
        static func receiveCoins(coins: Int) {
            coinsInBank += coins
        }
        }
        
        class Player {
        var coinsInPurse: Int
        init(coins: Int) {
            coinsInPurse = Bank.vendCoins(money:coins)
        }
        func winCoins(coins: Int) {
            coinsInPurse += Bank.vendCoins(money:coins)
        }
        deinit {
            Bank.receiveCoins(coins:coinsInPurse)
        }
        }
        
        
        
        print("Balance in Account: \(Bank.coinsInBank)")
        
         var Player1: Player? = Player(coins: 9000)
        
        
        
          print("Requested Amount to Withdraw: \(Player1!.coinsInPurse)")
        
          print("Balance After Withdraw: \(Bank.coinsInBank)")
        
         Player1 = nil
        
         print("Balance in Account: \(Bank.coinsInBank)")
        

        输出应该是这样的

        账户余额:10000 要求提取金额:9000 取款后余额:1000 账户余额:10000

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-09-07
          • 2012-09-22
          • 1970-01-01
          • 2012-12-23
          • 2021-07-13
          • 1970-01-01
          • 2010-12-30
          相关资源
          最近更新 更多