【问题标题】:Does 'pushViewController' Prevent the ViewController from Calling deinit?'pushViewController' 会阻止 ViewController 调用 deinit 吗?
【发布时间】:2017-10-06 03:05:23
【问题描述】:

我有几个视图控制器 (UIViewController)。 每个视图控制器都有自己的storyboard。我希望应用程序在从一个视图控制器转换到另一个视图控制器时调用deinit。但它不会。

应用以 HomeViewController 开头。当用户点击按钮 (UIButton) 时,它将转换到 SelectViewController。

class HomeViewController: BasicViewController {
    @IBAction func selectTapped(_ sender: UIButton) {
        let storyboard = UIStoryboard(name:"Select",bundle:nil)
        let controller = storyboard.instantiateViewController(withIdentifier: "SelectView") as! UINavigationController
        let viewController = controller.topViewController as! SelectViewController
        self.navigationController?.pushViewController(viewController, animated: true)    
    }

    deinit {
        print("HOME HAS BEEN REMOVED FROM MEMORY")
    }
}

应用离开 HomeViewController 时从不调用 deinit。我想知道这是不是因为它正在推动视图控制器?如果我如下设置视图控制器,应用程序将崩溃。我究竟做错了什么?我从来没有用不同的故事板做过。谢谢。

class HomeViewController: BasicViewController {
    @IBAction func selectTapped(_ sender: UIButton) {
        let storyboard = UIStoryboard(name:"Select",bundle:nil)
        let viewController = storyboard.instantiateViewController(withIdentifier: "SelectView") as! SelectViewController
        self.navigationController?.setViewControllers([viewController], animated: true)  
    }
}

更新 1

我猜就是下面这个。

@IBAction func selectTapped(_ sender: UIButton) {
    let storyboard = UIStoryboard(name:"Select",bundle:nil)
    let controller = storyboard.instantiateViewController(withIdentifier: "SelectView") as! UINavigationController
    self.present(controller, animated: true, completion: nil)
}

更新 2 当 SelectViewController 出现如下时,我也清除了视图控制器堆栈。

override func viewWillAppear(_ animated:Bool) {
    super.viewWillAppear(animated)

    var navigationArray = self.navigationController?.viewControllers
    navigationArray?.removeAll()
}

【问题讨论】:

  • 您可以使用从一个故事板到下一个故事板的故事板引用 - 无需在代码中执行此操作
  • @Ashley Mills 感谢您的提示。当他们有自己的故事板时,您可以从一个视图控制器转换到另一个视图控制器而无需编写代码?怎么样?
  • 将“故事板参考”拖到您的第一个故事板上 - 将其值设置为与您的第二个故事板上的视图控制器相对应。从您的按钮拖出一个链接到引用。
  • 嗯...我对故事板参考一无所知。非常感谢。
  • 使用故事板参考可以使应用程序从一个视图控制器过渡到另一个。但我也想知道如何在代码中做到这一点。

标签: ios swift swift3 uinavigationcontroller


【解决方案1】:

从您的代码 sn-p 中,我了解到您希望在 pushViewController 之后调用 deinit。但是,通过调用 pushViewController,您的导航控制器会将您的 HomeViewContoller 推送到导航堆栈,这意味着导航控制器拥有对您的 HomeViewController 对象的强引用。因此,不调用 deinit。如果您不需要 HomeViewController,则必须使用 SelectViewController 手动将其从导航堆栈中删除。 看看这个如何。 How to remove a specific view controller from uinavigationcontroller stack?

在 SelectViewController 中,

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  let allControllers = NSMutableArray(array: navigationController!.viewControllers)
  allControllers.removeObject(at: allControllers.count - 2)
  self.navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
}

【讨论】:

  • 谢谢。但这可能不会解决我的 deinit 问题,因为我什至使用 SelectViewController 的 viewWillAppear 调用从堆栈中删除所有视图控制器。
  • 嗯.. 这很奇怪,因为我按照我写的那样做,但我删除了 viewDidAppear。我知道下一个控制器的 viewWillAppear 在前一个控制器的 viewDidDisappear 之前被调用。您可以轻松检查。
【解决方案2】:

实际上,这与故事板无关。根据 Apple 的文档,“deinit”方法会在从内存中释放对象时自动调用,而不是在从当前对象推送视图控制器时自动调用。

当您从“HomeViewController”推送“SelectViewController”时,“HomeViewController”的实例不会从内存中释放,因此不会调用 deinit 方法。

这是 Apple 取消初始化文档的 link。或者,如果满足您的需要,您可以使用视图控制器的“viewDidDisappear”方法来执行操作。

【讨论】:

  • 好的。谢谢。那么如何从内存中删除 HomeViewController 呢?
  • @ElTomato 你不应该从内存中删除这个视图控制器。
  • 您可以从导航数组中删除视图控制器的对象,但在我看来这是不合逻辑的事情。您能告诉我您的具体要求是什么,以便我在可能的情况下为您提供适当的解决方案吗?
猜你喜欢
  • 2010-09-11
  • 1970-01-01
  • 2019-08-08
  • 2016-03-12
  • 2019-03-13
  • 2016-09-05
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多