3

如何在 c# Xamarin 中实现与 iOS 用于表视图的“委托”或“数据源”模式等效的模式?例如,我希望有如下视图类:

public class MyDataView : UIView
{
  public interface ISource
  {
    int NumberOfPages();
  }

  public ISource DataSource { get; set; }
}

但问题是当我使用以下代码从 MyViewController 调用它时:

this.myDataView.DataSource=new ViewSource(this)

public class ViewSource : MyDataView.ISource
{
  private readonly MyViewController parentController;

  public ViewSource(MyViewController parentController)
  {
    this.parentController=parentController;
  }
}

那么 MyViewController 永远不会因为创建了循环引用而被垃圾收集。

这似乎是一个普遍的要求,那么人们使用什么设计呢?

我应该让 Source 成为弱参考吗?在 C# 中是如何完成的?调用者可能不知道它是弱引用,这不是很危险吗?

4

3 回答 3

2

我建议您使用 Profiler 来查看这是否真的是内存泄漏。如果您发现这确实是一个问题,您可以使用WeakReferenceclass弱引用委托,该委托持有对对象的弱引用。

于 2013-09-03T16:04:02.917 回答
0

垃圾收集器非常有能力处理循环引用。你不必担心。

于 2013-08-31T10:31:21.957 回答
0

我个人经常在 MonoTouch 上与废弃的记忆作斗争。我现在要做的是调用 Dispose() 并将目标 c 层中存在的每个对象设置为 null。

public class AView : UIView {

    private UIView tip;
    private UIView top;

    protected override void Dispose(bool disposing) {
        base.Dispose(disposing);
        this.ReleaseDesignerOutlets();

        if (this.tip != null) {
            this.tip.Dispose();
            this.tip = null;
        }

        if (this.top != null) {
            this.top.Dispose();
            this.top = null;
        }
    }

}

我不认为“dealloc”绑定到 Dispose() 方法,因为只有当托管对象在托管环境中被 GC 收集时才会调用该方法。这并不意味着本机对象会死掉,它只是意味着托管环境中没有对它的引用。当本地对象要在托管环境中出现时,Mono 运行时会创建(或重用已创建的对象)一个托管对象,该对象绑定到本地对象并增加后者的引用计数器。当 GC 收集托管对象时,它会减少引用计数器。如果从未调用过 Dispose() 方法,则意味着 GC 没有收集对象,因此该对象仍有一个至少为 1 的 ref 计数器。

我现在要说的与我刚才所说的有些矛盾。我认为 Mono Runtime 不允许 GCed 对象再次出现在 C# 世界中(我们不想让神秘的新 C# 对象处于空状态,对吗?)。因此,在 ref 计数器正好为 1 之前,它们实际上不会对对象进行垃圾收集,即使该对象在托管环境中没有对它的引用。因此,当 GC 收集对象时,它们实际上是从内存中释放出来的。

在您的情况下(我认为)正在发生的事情是 View 持有对 DataSource 的引用,该 DataSource 持有对 ViewController 的引用。ViewController 没有被 GC,因为 View 持有对它的引用,即使没有指向该 View 的引用,GC 也不会收集它,因为对象的引用计数仍然为 2。事实上,原生世界中的 ViewController 有仍然是这个观点的参考。

于 2013-08-31T21:42:17.193 回答