如何修复由lambda事件处理程序引起的GC循环?

时间:2013-06-14 10:12:49

标签: c# mono xamarin.ios garbage-collection xamarin

通过Mark Probst和Rodrigo Kumpera观察Advanced Memory Management,我学习了一些新技术,例如分析Mono GC和使用WeakReference

然而,我仍然不明白如何从第28分钟“修复”拼图2:

public class CustomButton : UIButton {
    public CustomButton () { }
}

public class Puzzle2Controller : UIViewController
{
    public override void ViewDidLoad ()
    {
        var button = new CustomButton ();
        View.Add (button);
        button.TouchUpInside += (sender, e) =>
            this.RemoveFromParentViewController ();
    }
}

控制器拥有一个ref to按钮,该按钮包含一个ref事件处理程序,该处理程序将ref保存到控制器。

打破循环的一种方法是使按钮无效。 另一种方法是分离处理程序(但我们必须抛弃使用lamdas)。

是否有其他/更优雅/方法可以打破这个循环?我们能不能在这里坚持WeakReference

感谢。

编辑:在这种情况下,按钮甚至不是字段。但是还有一个周期,不是吗?它位于Controller的View的子视图中。我们必须清除它们吗?我很困惑。

1 个答案:

答案 0 :(得分:6)

在垃圾收集环境中, Cycles 通常不是问题 - 我必须从问题中假设这在单调处有所不同?编辑:不,我在这里的假设仍然有效 - 在你连接到它的视频中的7:50表示"扫描"丢弃了一个循环。

只要整个周期无法到达,周期就可以通常完全销售。这将是引用计数系统中的问题。

然而!关于你的问题 - 按钮(一旦添加)是否知道控制器?如果是这样,你可以从sender到达那里:

button.TouchUpInside += (sender, e) =>
            ((UIButton)sender).Parent.RemoveFromParentViewController();

此lambda现在不涉及捕获的变量,并且不涉及捕获上下文;它没有任何对控制器的引用 - 实际上大多数编译器会将它作为单个静态处理程序而不是每次使用的处理程序,因此它在委托创建方面也更有效。


具体说明单音的背景,然后是的,您需要使用WeakReference<T>

var controller = new WeakReference<Puzzle2Controller>(this);
button.TouchUpInside += (sender, e) => {
    var parent = controller.Object;
    if(parent != null) parent.RemoveFromParentViewController();
};