在MonoTouch中释放/处置UIView控制器



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

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

如何释放旧引用,这样我就不必每次都使用相同的 VC2 实例? Dispose似乎还不够。

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

差一点。MonoTouch 托管实例将保留对本机实例的引用。只要托管实例存在,本机实例就会处于活动状态(因为它们是引用计数的,MonoTouch 不会释放其引用(。

只要需要 MonoTouch 托管实例的

本机部分,就需要保留对 MonoTouch 托管实例的引用。

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

本机(目标 C(实例是引用计数,而不是垃圾回收。本机实例在其引用计数达到 0 之前不会释放(当关联的托管实例存在时不会发生这种情况(;

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

这会导致 ObjC 运行时立即EXC_BAD_ACCESS尝试访问它们。

这不会发生,至少不会这样。OTOH很难告诉您您的情况(没有看到代码和/或崩溃(。

怀疑你在托管实例完成作业之前(手动或非手动(处置它们。以下是可能发生的情况的简化

  • 您创建托管 MT。X 实例(例如UIView(;
  • 这将创建并引用本机 X(本机引用计数 == 1(;
  • 您在MT上覆盖事件(或添加委托...("ViewWillUnload"。X(也原生存在(;
  • 您分配 MT。X 实例到另一个(托管(实例,例如UIViewController;
  • 本机UIViewController将添加对本机 X 的引用(本机引用计数 == 2(;
  • 应用程序愉快地执行...
  • 您停止引用MT.X实例(例如,将变量设置为 null 或其他实例(;
  • 由于不再引用MT.X,因此垃圾回收器将释放托管实例,调用Dispose这将减少本机 X 的引用(本机引用计数 == 1(。但是本机实例不会被释放,因为它仍然被视图控制器引用(不是 0(;
  • UIViewController 会执行一些本地触发X.ViewWillUnload的操作(例如,它尝试加载新UIView(;
  • 由于X仍然本机存在(ref count == 1(,它将调用它的ViewWillUnload,这将尝试返回到托管实例...那被处理掉了

此问题的解决方案是确保在托管实例的本机部分完成其作业之前不会释放托管实例。

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

但是,当您像您一样调用Dispose方法时,我确实遇到了问题。似乎我们不应该手动执行此操作。相反,我们应该等待 GC 收集对象并释放其资源。基NSObject类在其终结器中调用Dispose,因此在收集对象时将释放所有非托管资源。

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

最新更新