62

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

这是推送的代码:

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

这是弹出的代码:

 self.navigationController?.popViewControllerAnimated(true)
4

13 回答 13

74

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

deinit {

}

结果它从未被调用过。
一旦我在正文中添加一些代码,它就开始按预期工作:

deinit {
    print("deinit called")
}

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

于 2015-11-07T07:30:42.797 回答
55

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

如果您的 UIViewController 创建了一个对象的实例,而该实例又对该视图控制器进行了“强”引用(例如,未明确声明为“弱”或“无主”的引用),并且您的视图控制器保持对该对象也不会被释放。这就是所谓的强引用循环,记录在这里(认真的 Swift 开发人员必须阅读):

Swift 编程语言 (Swift 3.0.1):自动引用计数

闭包是一个更隐蔽的情况,您可能会遇到麻烦。

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

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

于 2015-01-28T20:51:39.450 回答
18

我在给定页面上使用带有自定义序列的本教程自定义 TabBar。内存问题是由于子视图对父视图控制器有很强的引用。

class WBMNewsFeedV: UIView
{
   var parentVC:WBMHomeTabVC!
}

WBMNewsFeedV - 子类

parentVC:WBMHomeTabVC - 父类 ViewController

我将其更改为:

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

因此,强引用嵌套在子视图中,起初不可见。希望这对任何人都有帮助。更改后 deinit 总是被调用

WBMHomeTabVC

于 2015-05-20T08:54:43.490 回答
13

当 NotificationCenter 强烈引用受控的呈现视图时,我遇到了同样的问题,因此它永远不会被释放。所以我不得不像这样将[weak self]添加到块中:

(在 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)
    }
}
于 2016-11-03T03:24:13.113 回答
10

在 deinit 中添加一些行代码。如果您在 Empty deinit 处放置断点,编译器不会阻止您将其放在那里:

deinit {
print("any thing")
}

它会起作用的;)

于 2016-12-08T13:20:10.590 回答
7

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

于 2016-01-26T09:00:57.153 回答
6

我刚刚遇到了类似的问题。我的问题似乎是由对具有类类型协议的委托分配未指定为“弱”的控件的强引用引起的。

于 2015-05-05T14:45:47.597 回答
4

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

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

class SomeClass: NSObject {

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

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

于 2019-06-21T07:02:38.540 回答
3

只是为了添加一个我发现很难检测到的边缘情况:

如果您分配任何 UnsafeMutablePointers 并提供self(UIViewController)作为视图控制器内部的指针,请确保调用pointer.deinitialize(count:)不仅仅是pointer.deallocate().

否则,对的引用self将保留,并且 UIViewController 不会取消初始化。

于 2018-12-08T18:39:05.357 回答
2

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

于 2015-11-04T21:41:08.963 回答
1

我有一个类似的问题:我在详细视图控制器的滚动视图中包含了一些排列UIViews好的* stackview子视图。当我在后退按钮点击(您的视图控制器有类似的东西:(在某些情况下,当您单击“返回”并移至主视图时,这可能会阻止详细视图控制器被释放)UIViewswillMove(toParent parent: UIViewController?)let session = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())self

于 2019-03-03T12:00:16.053 回答
0

首先确保定义 deinit

deinit {
    print("OverlayView deinit")
}

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

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

var overlay: OverlayView?
overlay = nil

如果仍然没有调用dealloc,则可能存在如上所述的保留周期问题,在这种情况下,如果它回调此控制器(A)然后将其中一个设置为弱变量,您将不得不检查另一个视图控制器(B)。

于 2018-11-15T06:11:58.197 回答
0

在这个问题中我能找到的最有帮助的材料是链接

但对我来说问题是typealias

于 2019-11-01T07:29:26.450 回答