为啥关闭视图控制器不会从内存中清除呈现的控制器?

Posted

技术标签:

【中文标题】为啥关闭视图控制器不会从内存中清除呈现的控制器?【英文标题】:Why dismissing view controller is not clearing presented controller from memory?为什么关闭视图控制器不会从内存中清除呈现的控制器? 【发布时间】:2015-04-28 09:55:22 【问题描述】:

我有 2 个控制器。他们每个人在屏幕上只有一个按钮。对于第一个控制器按钮正在模态地呈现第二个控制器,而对于第二个控制器按钮正在关闭呈现的控制器。

第一个的代码很简单:

class ViewController: UIViewController 
    @IBAction func present(sender: AnyObject) 
        let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
        if let controller = storyboard.instantiateViewControllerWithIdentifier("web") as? UIViewController 
            controller.modalTransitionStyle = UIModalTransitionStyle.FlipHorizontal
            self.presentViewController(controller, animated: true, completion: nil)
        
    

第二个控制器代码包含一些额外的代码,用于检测关闭控制器后仍然存在。

static var index: Int = 0
var index: Int

required init(coder aDecoder: NSCoder) 
    self.index = WebViewController.index++
    super.init(coder: aDecoder)
    let timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "action", userInfo: nil, repeats: true)


func action() 
    NSLog("Class \(self.dynamicType) index is \(self.index)")

第二个控制器的所有代码如下:

class WebViewController: UIViewController 
    static var index: Int = 0
    var index: Int

    required init(coder aDecoder: NSCoder) 
        self.index = WebViewController.index++
        super.init(coder: aDecoder)
        let timer = NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "action", userInfo: nil, repeats: true)
    

    func action() 
        NSLog("Class \(self.view) index is \(self.index)")
    

    @IBAction func dismissSelf() 
        if let presentingController = self.presentingViewController 
            presentingController.dismissViewControllerAnimated(true, completion: nil)
        
    

因此,当您第一次运行此程序并在第一个控制器屏幕上按下按钮时,每 5 秒您将在控制台中看到如下内容:

类 Proj.WebViewController 索引为 0

但是,如果您将关闭控制器并再次呈现,那么您将看到两者:

类 Proj.WebViewController 索引为 0

类 Proj.WebViewController 索引为 1

据我所知,即使没有人从我身边抓住他,解雇也不会从内存中删除。

有人知道它是什么,我该如何解决?

也可以下载sample project

【问题讨论】:

【参考方案1】:

计时器正在捕获您的视图控制器

您应该为计时器保留一个弱引用,并在dismissSelf 中添加timer.invalidate()

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/index.html#//apple_ref/occ/instm/NSTimer/invalidate

【讨论】:

你成就了我的一天 【参考方案2】:

很快,如果你的对象被使用,那么编译器就会明白它会被使用,所以即使你dismissViewControllerAnimatedUIViewController。它不会是dealloc。所以你需要在dismissViewControllerAnimated 被解雇之前invalidate() 计时器。这里dealloc 替换为deinit

@IBAction func dismissSelf() 
        timer.invalidate()
        self.dismissViewControllerAnimated(true, completion: nil)
    

deinit 

        self.view.removeFromSuperview()
        println("call")
        // perform the deinitialization
    

希望对您有所帮助。

【讨论】:

【参考方案3】:

阅读更多

swift-nstimer-tutorial-lets-create-a-counter-application &simple-stopwatch-app-in-swift

NSTimer_Class

使用这个...

@IBAction func dismissSelf() 
        if let presentingController = self.presentingViewController 
            timer.invalidate()// add this
            presentingController.dismissViewControllerAnimated(true, completion: nil)
        
    

【讨论】:

【参考方案4】:

我也遇到过这种情况“为什么关闭视图控制器不会从内存中清除呈现的控制器?”。所以就我而言,我有

FirstViewController: UIViewController 
var secondViewController: SecondViewController
 override func viewDidLoad() 
      super.viewDidLoad()
      //Important...Don't Do instantiation here....
      //Instantiate only when it's going to be used
      secondViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
 
 @IBAction fun buttonAction() 
     self.present(secondViewController, animated: true)
 

上面的代码没有在我的 SecondViewController

上调用 deinit

对我有用的修复:

FirstViewController: UIViewController 
var secondViewController: SecondViewController
 override func viewDidLoad() 
      super.viewDidLoad()
 
 @IBAction fun buttonAction() 
     //Do the instantiation here 
     secondViewController = UIStoryboard.init(name: "Main", bundle: nil)
                            .instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController
     self.present(secondViewController, animated: true)
     //setting the view controller reference variable to nil
     self.secondViewController = nil
 

SecondViewController 的引用一直保留在 SecondViewController 变量上,直到它被重新初始化或设置为 nil。

【讨论】:

以上是关于为啥关闭视图控制器不会从内存中清除呈现的控制器?的主要内容,如果未能解决你的问题,请参考以下文章

视图控制器不会立即关闭并呈现新的视图控制器

在模态视图控制器上模拟内存警告清除前一个控制器的内容

如何从 appdelegate 呈现和关闭模态视图?

关闭模态视图控制器后呈现不同的视图控制器

在关闭另一个模式视图控制器后呈现一个模式视图控制器

关闭从模态呈现的视图控制器翻转的视图控制器