我有一个具有复杂视图层次结构的应用程序,其中一个视图控制器(让我们称之为RootVC)可以导致许多其他视图。当我弹出RootVC时,我想完全释放它。我没有将参考文献存储在字段或其他地方,并认为这就足够了。但是最近我检查了Xamarin的Heap Shot并在“All objects”部分看到RootVC的许多实例仍留在内存中。
例如:
sealed class VC1 : UIViewController
{
...
private void OpenVC2()
{
var vc2 = new VC2();
NavigationController.PushViewController(vc2, true);
}
}
sealed class VC2 : UIViewController
{
private UIButton button;
public override ViewDidLoad()
{
...
button = new UIButton(frame);
button.TouchUpInside += HandleButtonTouch;
...
}
private void HandleButtonTouch(object sender, EventArgs e)
{
NavigationController.PopViewControllerAnimated(true):
}
}
以下是Heap Shot屏幕截图的链接(由于信誉不佳,无法将其发布为图片) - http://imgur.com/a/3MYBr#1
当我在VC2上时,我会在第一个屏幕截图中看到类似内容。
当我弹出VC2和VC1时,Heap Shot在第二张图像上显示。
出现几个VC2之后,它看起来像第三个截图。
他们永远不会被处理或最终确定,直到最后。即使通过根也无法达到它们。这是不可接受的,因为内存是有限的,并且所有这些VC2都在内存中,我们很容易得到内存警告或应用程序终止。
但是,如果我订阅/取消订阅View上的按钮事件,就会显示/消失:
sealed class VC2 : UIViewController
{
private UIButton button;
public override ViewDidLoad()
{
...
button = new UIButton(frame);
...
}
public override void ViewWillAppear(bool animated)
{
...
button.TouchUpInside += HandleButtonTouch;
}
public override void ViewDidDisappear(bool animated)
{
...
button.TouchUpInside -= HandleButtonTouch;
}
private void HandleButtonTouch(object sender, EventArgs e)
{
NavigationController.PopViewControllerAnimated(true):
}
}
在这种情况下,VC2(及其所有视图等)在消失时会正确处理。调用~VC2(),并且Heap Shot中不再显示所有VC2。
所以,这是问题所在。我做错了什么?我应该订阅/取消订阅上述控制事件吗?或者这是Xamarin.iOS的内存泄漏?
答案 0 :(得分:3)
会发生的是循环依赖(使用事件处理程序)跨越本机管理的边界,并且当前Xamarin.iOS运行时/ GC无法检测到此情况。
您已经找到了解决此问题的方法:通过删除事件处理程序来打破循环依赖关系。
以下是详细说明情况的视频:http://xamarin.com/evolve/2013#session-0w86u7bco2