在MonoTouch中释放/处置UIViewController

时间:2012-07-23 09:00:36

标签: objective-c uiviewcontroller garbage-collection xamarin.ios didreceivememorywarning

据我了解,我们需要在MonoTouch中处理它们时保持对Cocoa对象的引用。这样做的原因是ObjC运行时可能仍然保持对对象的引用,如果我们没有" MonoTouch引用"在它们上面,它们可以被垃圾收集,一旦ObjC运行时试图访问它们就会产生EXC_BAD_ACCESS

说,我们有两个UIViewController子类,VC1和VC2。如果用户单击VC1上的按钮,则UI导航到VC2,用户可以来回导航。如果我每次用户导航到VC2时都会创建一个新的VC2实例,那么对旧实例的引用就会丢失,因此它们会被垃圾收集,并且下次didReceiveMemoryWarning传播到应用程序时应用程序会崩溃UIViewControllers。

如何发布旧引用,所以我不必每次都使用相同的VC2实例? Dispose似乎还不够。

2 个答案:

答案 0 :(得分:6)

  

据我了解,我们需要在MonoTouch中处理它们时保留对Cocoa对象的引用。

不完全。 MonoTouch 托管实例将保留对原生实例的引用。只要托管实例存在,原生实例将处于活动状态(因为它们是引用计数而MonoTouch不会释放它的引用)。

只要需要原生部分,您就需要保留对MonoTouch 托管实例的引用。

  

原因是ObjC运行时可能仍然保持对对象的引用......它们可能被垃圾收集,

Native(Objective C)实例是引用计数,而不是垃圾收集。原始实例在引用计数达到0之前不会被释放(当关联的托管实例存在时不会发生);

本机实例也可以保存对其他本机实例的引用。并非每个原生实例都有相应的托管实例。

  

一旦ObjC运行时尝试访问它们,就会产生EXC_BAD_ACCESS。

这不会发生,至少不是这样。 OTOH很难告诉你在你的情况下发生了什么(没有看到代码和/或崩溃)。

怀疑您在完成作业之前(手动或非手动)处置托管实例。这是可能发生的简化

  • 您创建托管 MT.X实例(例如UIView);
  • 这会创建并引用 native X(本机引用计数== 1);
  • 你在MT.X上覆盖一个事件(或添加一个委托......)`ViewWillUnload'(它本身也存在);
  • 您将MT.X实例分配给另一个(托管)实例,例如UIViewController;
  • 原生 UIViewController将添加对原生 X的引用(原生引用计数== 2);
  • 应用程序执行得很开心......
  • 您停止引用MT.X实例(例如,将变量设置为null或其他实例);
  • 由于不再引用MT.X垃圾收集器将处置托管实例,调用Dispose减少对< em> native X(本机引用计数== 1)。但 native 实例将不会被释放,因为视图控制器仍然引用它(而不是0);
  • UIViewController执行的操作本身就是X.ViewWillUnload(例如,它会尝试加载新的UIView);
  • 由于X仍然存在(引用次数== 1),因此会调用它ViewWillUnload,它会尝试返回托管实例...那是的设置即可。

此问题的解决方案是确保在原生部分完成其工作之前,不要处置托管实例。

答案 1 :(得分:1)

我的应用程序中的情况相同,GC正确收集对象。换句话说,我从来没有遇到过简单地将VC引用归零并让GC完成其余工作的问题。

但是,我在调用Dispose方法时遇到问题。看来我们不应该手动执行此操作。相反,我们应该等待GC收集对象并释放其资源。 Base NSObject类在其终结器中调用Dispose,因此在收集对象时将释放所有非托管资源。

您也可以在某些根VC的GC.Collect方法中调用DidReceiveMemoryWarning