在MonoTouch中释放/处置UIViewController

che*_*ica 5 garbage-collection objective-c uiviewcontroller xamarin.ios didreceivememorywarning

据我了解,我们需要在MonoTouch中处理它们时保持对Cocoa对象的引用.这样做的原因是ObjC运行时可能仍然保持对对象的引用,如果我们没有"MonoTouch引用",它们可能被垃圾收集,这会导致EXC_BAD_ACCESSObjC运行时尝试访问它们.

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

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

pou*_*pou 6

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

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

Iow您需要保留对MonoTouch 托管实例的引用,只要它们的本机部分是必需的.

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

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

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

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

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

怀疑你在托管实例完成工作之前(手动或不手动)处置它们.这里简化了可能发生的事情:

  • 你创建一个托管的 MT.X实例(例如一个UIView);
  • 这创建并引用本机 X(本机引用计数== 1);
  • 你在MT.X上覆盖一个事件(或添加一个委托...)`ViewWillUnload'(它本身也存在);
  • 您将MT.X实例分配给另一个(托管)实例,例如UIViewController;
  • UIViewController将添加对本 X的引用(本机引用计数== 2);
  • 应用程序执行愉快...
  • 你停止对MT.X实例的引用(例如,将变量设置为null或不同的实例);
  • 因为没有引用MT.X垃圾收集器将处理托管实例,调用Dispose减少本机 X 的引用(本机引用计数== 1).但是本实例不会被释放,因为它仍然被视图控制器引用(而不是0);
  • UIViewController做一些事情触发,本机,X.ViewWillUnload(例如,它会尝试加载一个新的UIView);
  • 因为X仍然存在本地(引用计数== 1),它将调用它将ViewWillUnload尝试返回托管实例...已被处置.

此问题的解决方案是确保在本机部件完成其作业之前确保您不会处置托管实例.