4

我正在编写的应用程序需要支持 iOS5+。最近,Apple 过时ViewDidUnload了,因为我们被告知在发布内存警告视图时没有显着的内存增益。

在我的应用程序中,我有一个UIViewController管理非常重的UIWebView.
此视图控制器以模态方式呈现,因此经常被创建和关闭。

通过使用 Instruments,我发现它所占用的内存UIWebView在其控制器被解除后并没有立即被释放。

我假设控制器最终会被 Mono GC 收集,它会调用Dispose控制器及其视图,这将处理UIWebView和释放底层的原生对象。

我无法测试是否是这种情况:不幸的是,在展示和关闭控制器大约十次后,我收到内存警告,应用程序在下一秒崩溃。我不确定 Mono GC 是否有机会运行。

所以我所做的是GC.Collect在控制器被解雇后立即添加呼叫。
我还必须添加ReleaseDesignerOutlets.ViewDidDisappear

这似乎是免费UIWebView的。

更新:我已经发现ReleaseDesignerOutlets调用ViewDidDisappear显然是在释放 web 视图,但是 GC 调用没有任何好处。事实上,GC 从未收集过我的控制器,因为按钮单击处理程序使整个控制器保持活动状态

现在,我完全迷失在某种 Cargo 内存管理中。

  1. 在我的情况下强制垃圾收集是否合理?
  2. 为什么我必须打电话ReleaseDesignerOutlets?当然,如果没有对“死”控制器的引用,它的视图也应该被认为有资格被收集?
  3. 从 Instruments 的 heapshot diff 来看,看起来从代码“等待”到控制器创建的视图也是如此。我必须处理它们吗?取消他们?
  4. 我需要手动调用Dispose刚刚解散的控制器吗?
  5. 我需要在我的控制器 ReleaseDesignerOutlets的方法中包含调用吗?Dispose
  6. UIView我是否需要在我的自定义子类中取消对子视图的引用Dispose
4

2 回答 2

4

您应该Dispose()在控制器关闭时调用它。

所以像:

private YourModalController modalController;

//When your button is clicked
partial void YourButtonClick() {
  modalController = new YourModalController();
  PresentViewController(modalController, true, delegate {
    modalController.Dispose();
    modalController = null;
  });
}

YourModalController中,确保您有:

public override void Dispose(bool disposing) {
  ReleaseDesignerOutlets();
  base.Dispose(disposing);
}

在这种情况下,您不必担心ViewDidUnload,因为此控制器在解除时被释放。

在 iOS 6 之前:

  • ViewDidUnload在应用程序的内存不足警告中被调用
  • 在仍在内存中的控制器上,但不在屏幕上,例如在堆栈中UINavigationController
  • 在此事件中,您应该处置您有 C# 引用的所有视图并将它们设置为 null
  • 对于 iOS 6,这不再发生

同样,如果你有这个:

private UIButton buttonIMadeFromCode;

您应该检查 null,处理它,并将其设置为 null in Dispose()and ViewDidUnload()(但只有ViewDidUnload在您的目标小于 iOS 6 时才会弄乱)。

于 2012-10-24T17:15:01.623 回答
1

首先:MonoTouch 中的内存管理是一个非常复杂的话题,因为 MonoTouch(垃圾回收)必须与 ObjectiveC(引用计数)共存。

正如您现在发现的那样,很容易陷入循环,并且当这些越过 MonoTouch/ObjectiveC 边界时,GC 无法准确判断发生了什么并释放整个循环。

如果您对更深入的解释感兴趣,请查看此线程

于 2012-10-24T22:17:28.053 回答