Deinit没有调用UIViewController,但是Dealloc是

Sen*_*ful 19 memory-management objective-c uiviewcontroller ios swift

看起来像雨燕相当于deallocISdeinit.但是,当您尝试在UIViewController上定义方法时,它的行为并不像您期望的那样......

建立

  1. 使用Xcode 7.0在Swift或Objective-C中创建一个新的Single View项目.
  2. 在使用storyboard创建的视图控制器上添加"dismiss"按钮(我将此视图控制器称为VC2;其类为ViewController).
  3. 添加一个新的视图控制器并将其设置为初始视图控制器(VC1,类为零).
  4. 向VC1添加"present"按钮,其中"Present Modally"segue到VC2.
  5. 在VC2的代码中,在deinit(Swift)或dealloc(Objective-C)中放置一个断点.
  6. 在VC2中,使"解除"按钮的操作执行以下操作:

    // Swift:
    presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
    
    // Objective-C:
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
    
    Run Code Online (Sandbox Code Playgroud)
  7. 运行应用程序并点击两个按钮以首先显示VC2,然后将其关闭.

请注意,在Objective-C中,dealloc断点被击中.

斯威夫特,在另一方面,deinit断点永远不会命中.

为什么deinit从未打电话?这是一个bug还是设计?

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


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

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

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

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

鉴于上述设置,视图控制器应该没有强大的参考周期.

Sen*_*ful 31

TLDR:

断点仅在deinit前面有可执行代码行时才有效.

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

感谢Adam让我指出了正确的方向.我没有进行大量的测试,但看起来断点的行为与deinit代码中的其他地方的行为不同.

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

通常情况下,即使方法无效,断点也会受到严重影响:

? 1
? 2  func doNothing() {
? 3 
? 4  }
  5
Run Code Online (Sandbox Code Playgroud)

但是,在一个空白deinit方法中,NO断点将会被击中:

  1
  2  deinit {
  3 
  4  }
  5
Run Code Online (Sandbox Code Playgroud)

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

? 1 
? 2  deinit {
? 3      //
? 4      doNothing()
? 5      //
? 6      foo = "abc"
  7      //
  8  }
  9
Run Code Online (Sandbox Code Playgroud)

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

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

? 1  
? 2  deinit {
? 3      number++
  4  //    incrementNumber()
  5  }
  6
Run Code Online (Sandbox Code Playgroud)

注意:对于在同一行上暂停执行的断点,它们将按创建顺序命中.为了测试他们的顺序,我设置了一个断点到Log Message在评估操作后自动继续.

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

注意:这都在Xcode 7.1.1中进行了测试


Ada*_*ell 5

我还没有尝试过,但我确实为你找到了这个:

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

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