Deinit没有调用UIViewController,但是Dealloc是

时间:2015-10-13 20:35:50

标签: ios objective-c swift memory-management uiviewcontroller

seems like the Swift equivalent of dealloc is deinit。但是,当您尝试在UIViewController上定义方法时,它的行为并不像您期望的那样......

设置

  1. 使用Xcode 7.0在Swift或Objective-C中创建一个新的Single View项目。
  2. 添加"解雇"使用故事板创建的视图控制器上的按钮(我将此视图控制器称为VC2;其类为ViewController)。
  3. 添加新的视图控制器并将其设置为初始视图控制器(VC1,类为nil)。
  4. 添加"礼物"使用"按模式显示"按钮到VC1 segue to VC2。
  5. 在VC2的代码中,在deinit(Swift)或dealloc(Objective-C)中放置一个断点。
  6. 在VC2中,进行"解雇"按钮的操作执行以下操作:

    // Swift:
    presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
    
    // Objective-C:
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
    
  7. 运行应用程序并点击两个按钮,先显示VC2,然后将其关闭。
  8. 请注意 Objective-C 如何点击dealloc断点

    另一方面,在 Swift 中, deinit断点永远不会被击中

    为什么deinit从未被调用过?这是一个错误还是设计错误?

    如果这是设计的,那么当不再需要视图控制器时,我应该在哪里放置清理代码以释放资源? (它不能放在viewDidUnload中,因为该方法已被弃用。它不能出现在viewDidDisappear中,因为其他内容可能会持有对它的引用,并最终会再次显示它。 )

    注意:如果您尝试在Swift中定义dealloc方法,则会收到以下错误:

      

    方法' dealloc()'使用Objective-C选择器' dealloc'与使用相同的Objective-C选择器的deinitializer冲突。

    如果Swift视图控制器继承自Objective-C控制器,并且在Objective-C dealloc方法中放置了断点,您将获得上面定义的相同错误行为:deinit将不会调用,但dealloc将被调用。

    如果您尝试使用Allocations查看内存中类的实例数,则两个版本都显示相同的内容:# Persistent始终为1,每次显示时# Transient都会增加第二个视图控制器。

    鉴于上述设置,视频控制器应该没有strong reference cycle

2 个答案:

答案 0 :(得分:30)

TLDR:

如果前面有可执行的代码行,则断点仅在deinit中有效。

  • 如果在可执行代码行上放置断点,那么它将起作用。
  • 可执行的代码行必须属于deinit方法。

感谢Adam for pointing me in the right direction。我没有做过大量的测试,但看起来deinit中断点的行为与代码中的其他地方的行为不同。

我将向您展示几个示例,其中我在每个行号上添加了断点。那些可行的(例如暂停执行或执行其操作,如记录消息)将通过➤符号表示。

正常情况下,断点会被大量击中,即使方法无效:

➤ 1
➤ 2  func doNothing() {
➤ 3 
➤ 4  }
  5

但是,在空白deinit方法中,断点将会受到影响:

  1
  2  deinit {
  3 
  4  }
  5

通过添加更多代码行,我们可以看到它取决于断点后面是否有可执行的代码行:

➤ 1 
➤ 2  deinit {
➤ 3      //
➤ 4      doNothing()
➤ 5      //
➤ 6      foo = "abc"
  7      //
  8  }
  9

特别要密切关注第7行和第8行,因为这与doNothing()的表现有很大不同!

如果您已经习惯了第4行断点在doNothing()中的工作方式,那么如果在第5行(甚至4)上只有断点,则可能会错误地推断出您的代码没有执行这个例子:

➤ 1  
➤ 2  deinit {
➤ 3      number++
  4  //    incrementNumber()
  5  }
  6

注意:对于在同一行暂停执行的断点,它们按创建顺序命中。为了测试他们的顺序,我设置了一个断点到日志消息评估行动后自动继续

注意:在我的测试中,还有另一个潜在的陷阱可能会让你:如果使用print("test"),它会弹出调试区域以显示消息(消息以粗体显示) 。但是,如果您添加断点并告诉它记录消息,它将以常规文本记录它,弹出打开调试区域。您必须手动打开调试区域才能看到输出。

注意:这都是在Xcode 7.1.1中测试的

答案 1 :(得分:5)

我还没有尝试过,但我找到了this给你:

似乎函数不会被调用,除非一些代码被放入deinit(怪异)必须是swift优化阶段的一部分。

尝试按照建议在您的deinit中放置打印声明并报告您的发现