为啥关闭视图控制器不会从内存中清除呈现的控制器?
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】:很快,如果你的对象被使用,那么编译器就会明白它会被使用,所以即使你dismissViewControllerAnimated
UIViewController
。它不会是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。
【讨论】:
以上是关于为啥关闭视图控制器不会从内存中清除呈现的控制器?的主要内容,如果未能解决你的问题,请参考以下文章