Deinit从未打电话过

时间:2014-11-17 11:11:58

标签: swift uinavigationcontroller deinit

我正在创建一个ViewController对象,将其推送到导航控制器。 当从堆栈弹出对象时 - 它没有被释放而Deinit没有被调用。可能是什么原因?

以下是推送的代码:

self.navigationController?.pushViewController(CustomViewController(), animated: true)

这是弹出的代码:

 self.navigationController?.popViewControllerAnimated(true)

13 个答案:

答案 0 :(得分:58)

我有类似的问题。我在我的类中添加了空deinit方法并添加了断点:

deinit {

}

结果它从未被调用过。
只要我向主体添加一些代码,它就会按预期开始工作:

deinit {
    print("deinit called")
}

因此,请确保您的deinit方法不为空 PS。我使用的是Swift 2,Xcode 7.1

答案 1 :(得分:41)

您的任何类或其包含的属性是否会引用您弹出的视图控制器?

如果您的UIViewController已经创建了一个对象实例,而该对象又对该视图控制器进行了“强大”引用(例如,未明确声明为'weak'或'unowned'的引用),并且您的视图控制器保持对该对象的强烈引用也不会被解除分配。这被称为一个强大的参考周期,在这里记录(严格的Swift开发人员必读):

The Swift Programming Language (Swift 3.0.1): Automatic Reference Counting

闭包是一个更加阴险的案例,你可能会遇到麻烦。

您可以尝试作为实验的一件事是推动控制器并在之前将其弹出您在viewDidLoad或初始化中执行任何操作,并查看是否正在调用deinit方法。如果是,那么你应该能够逐步发现你正在做的事情,这会导致你所看到的症状。

另一件可以阻止诊断的事情(正如其他答案所指出的那样),我学到了很难的方法,如果deinit方法不包含可执行语句,调试器断点将不会被用于deinit(),因为操作系统或编译器如果它为空则优化deinit调用,所以如果你想验证deinit()被调用,至少要在那里放一个print语句。

答案 2 :(得分:15)

我在给定页面上使用本教程Custom TabBar和自定义seque。内存问题是由于子视图具有父视图控制器的强引用。

class WBMNewsFeedV: UIView
{
   var parentVC:WBMHomeTabVC!
}
  

WBMNewsFeedV - 子类

     

parentVC:WBMHomeTabVC - 父类ViewController

我把它改为:

class WBMNewsFeedV: UIView
{
    weak var parentVC:WBMHomeTabVC!
}

因此,强引用嵌套在子视图中,并且最初不可见。希望这有助于任何人。改变之后,总是在

中调用deinit
  

WBMHomeTabVC

答案 3 :(得分:9)

当NotificationCenter对所呈现的视图进行强烈引用时,我遇到了同样的问题,因此它永远不会被释放。所以我不得不像这样添加 [弱自我]

(在viewDidLoad中)

NotificationCenter.default.addObserver(forName: .showFoo, object: nil, 
  queue: OperationQueue.main) { [weak self] (notification) in
    if let foo = notification.userInfo?["foo"] as? Foo {
            self?.afooButton!.setImage(UIImage(named: "foo"), for: .normal)
    }
}

答案 4 :(得分:6)

我的视图控制器中有一个计时器,每分钟运行一次以更新标签。我用deinit打电话来使计时器无效,我非常确定这是我在Objective-C(dealloc)中总是做的并且它有效。但是在Swift中似乎有点不同,所以我将时间创建/失效代码移动到viewWillAppear / viewWillDisappear(真的更有意义),现在一切似乎都很好了!

答案 5 :(得分:5)

我刚遇到类似的问题。我的问题似乎是由于对控件的强烈引用引起的,该控件的代理分配未被指定为“弱”'使用类类型协议。

答案 6 :(得分:5)

添加一些deinit的行代码。如果你把断点放在Empty deinit,编译器不会阻止你 把这个:

deinit {
print("any thing")
}

它会起作用;)

答案 7 :(得分:1)

我遇到了同样的问题。在我的例子中,UIView.animateWithDuration的永无止境的循环......将ViewController保存在Memory中并阻止deinit的调用。如果您使用这样的东西,您必须先停止它,然后删除ViewController。希望有所帮助。

答案 8 :(得分:1)

只需添加一个我发现很难检测到的边缘保护套:

如果您分配了任何UnsafeMutablePointers并在视图控制器内部提供self(UIViewController)作为指针,请确保仅{{1}调用pointer.deinitialize(count:) }。

否则,将保留对pointer.deallocate()的引用,并且UIViewController不会取消初始化。

答案 9 :(得分:1)

我遇到了同样的问题,我发现我没有为其他班级代表做薄弱的参考

protocol SomeClassDelegate : AnyObject {
    func someClassDelegateMethod(<param>)
}

class SomeClass: NSObject {

    // Make delegate weak reference 
    weak var delegate:InfractionDataManagerDelegate? = nil
    < some code >
}

现在在我的实现类上正在调用 deinit

答案 10 :(得分:0)

首先请确保定义deinit

deinit {
    print("OverlayView deinit")
}

使用Xcode的对象图来检查正在创建的实例数量,如果实例没有被释放,它们将继续增长。 我正在文件顶部创建另一个ViewController的属性,因此我将其移动并将其放置在解决了我的问题的使用范围内。然后它的deinit开始调用。

此外,我使用uiview属性显示需要在某些地方从我的viewcontroller访问的叠加层,我将其设为可选,并在对其调用removefromsuperview后将其设置为nil。

var overlay: OverlayView?
overlay = nil

如果仍然取消分配未调用,则可能存在如上所述的保留周期问题,在这种情况下,您还必须检查另一个viewcontroller(B)(如果它回调此控制器(A)),然后将其中一个设置为弱变量。

答案 11 :(得分:0)

我有一个类似的问题:我有一个UIViews作为详细视图控制器的 scrollview 中包含的* stackview的排列子视图。当我从后退按钮点击(UIViews上的 stackview 中移除willMove(toParent parent: UIViewController?)时可以正常工作。另一件事要检查的是,当您在视图控制器中看到类似{{1 }}(在某些情况下,当您单击 Back 并移至母版时,let session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())可能会阻止重新分配局部视图控制器)

答案 12 :(得分:0)

在这个问题上我能找到的最有帮助的材料是link

但是对我来说,问题是typealias