5

观看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 ();
    }
}

控制器持有一个对按钮的引用,该按钮持有对事件处理程序的引用,事件处理程序持有对控制器的引用。

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

还有其他/更优雅/打破循环的方法吗?我们可以以某种方式坚持WeakReference在这里吗?

谢谢。

编辑:在这种情况下,按钮甚至不是一个字段。但还是有一个循环,不是吗?它在控制器视图的子视图中。我们必须清除它们吗?我很困惑。

4

1 回答 1

6

在垃圾收集环境中,循环通常不是问题——我必须从这个问题中假设这在单点触控中有所不同?编辑:不,我的假设在这里仍然有效 - 在您链接到它的视频中的 7:50 展示了一个循环被“扫描”丢弃。

一旦整个周期变得无法到达,通常可以放弃整个周期这在引用计数系统中将是一个问题。

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

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

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


具体来说就是monotouch的上下文,那么是的,你需要使用WeakReference<T>

var controller = new WeakReference<Puzzle2Controller>(this);
button.TouchUpInside += (sender, e) => {
    var parent = controller.Object;
    if(parent != null) parent.RemoveFromParentViewController();
};
于 2013-06-14T10:17:19.433 回答