简体   繁体   English

如何在c#Xamarin中实现ios委托/数据源模式?

[英]How to implement the ios delegate / data source pattern in c# Xamarin?

How can I implement the equivalent to the "delegate" or "data source" pattern that iOS uses for table views, in c# Xamarin? 如何在c#Xamarin中实现iOS用于表视图的“委托”或“数据源”模式的等效模式? For example, I'd like to have view classes like: 例如,我想要查看类:

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

  public ISource DataSource { get; set; }
}

but the problem is when I call this from MyViewController with code like: 但问题是当我从MyViewController调用此代码时,代码如下:

this.myDataView.DataSource=new ViewSource(this)

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

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

then MyViewController can never be garbage collected because of the circular reference created. 然后,由于创建了循环引用,MyViewController永远不会被垃圾收集。

This seems like a common requirement, so what design do people use? 这似乎是一个常见的要求,那么人们使用什么样的设计呢?

Should I make Source a weak reference? 我应该将Source作为弱参考吗? How is that done in c#? 怎么在c#中完成? And isn't that dangerous as the caller may not know its a weak reference? 并不是那么危险,因为来电者可能不知道它的弱引用?

I'd suggest you to use the Profiler to see if that's really a memory leak. 我建议你使用Profiler来查看这是否真的是内存泄漏。 If you find that it's really an issue, you may weak reference the delegate using WeakReference class , that holds a weak reference to an object. 如果您发现它确实是一个问题,您可能会使用WeakReference弱引用该委托, 该类包含对象的弱引用。

The garbage collector is quite capable of handling circular references. 垃圾收集器非常能够处理循环引用。 You don't have to worry about it. 你不必担心它。

I personally struggled often with abandoned memory on MonoTouch. 我个人经常在MonoTouch上放弃记忆。 What I do now is that I call Dispose() and set null every objects that exist in the objective c layer. 我现在所做的是调用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;
        }
    }

}

I don't think that "dealloc" is bound to the Dispose() method, as this one is only called when the managed object gets collected by the GC in the managed environment. 我不认为“dealloc”与Dispose()方法绑定,因为只有在托管环境中GC收集托管对象时才会调用此方法。 It doesn't mean that the native object is gonna die, it just means that there is no reference in the managed environment to it. 这并不意味着本机对象会死,它只是意味着托管环境中没有引用它。 When a native object is going to surface in the managed environment, the Mono runtime creates (or reuse the one already created) a managed object that binds to the native one and increase the reference counter of the latter. 当本机对象将在托管环境中浮出水面时,Mono运行时创建(或重用已创建的对象)一个托管对象,该托管对象绑定到本机对象并增加后者的引用计数器。 When GC collects the managed object, it decreases the reference counter. GC收集托管对象时,会减少引用计数器。 If the Dispose() methods is never called though, it means that the GC didn't collect the object and therefore the object has still a ref counter that is at least one. 如果从不调用Dispose()方法,则意味着GC没有收集对象,因此该对象仍然具有至少为1的ref计数器。

What I'm going to say now is going to contradict a little against what I just said. 我现在要说的是与我刚才所说的相矛盾。 I think that the Mono Runtime doesn't allow a GCed object to surface again into the C# World (we don't want to have mysterious new C# objects with an empty state do we?). 我认为Mono Runtime不允许GCed对象再次浮出水面进入C#World(我们不希望神秘的新C#对象具有空状态吗?)。 Thus, they actually don't garbage collect the object until the ref counter is at exactly one, even though the object has no reference to it in the managed environment. 因此,即使对象在托管环境中没有引用它,它们实际上也不会垃圾收集对象,直到ref计数器正好为1。 Therefore, when GC collects the object, they are actually released from the memory. 因此,当GC收集对象时,它们实际上是从内存中释放的。

What (I think) is going on in your case is the View holds a reference to a DataSource that holds a reference to a ViewController. 在你的情况下(我认为)正在进行的是View保存对DataSource的引用,该DataSource包含对ViewController的引用。 The ViewController is not GCed because the View holds a reference to it and even if no reference points to this View, the GC doesn't collect it because the object still has a ref count of 2. Indeed, the ViewController in the native world has still a reference to this view. ViewController不是GCed,因为View保存了对它的引用,即使没有引用指向此View,GC也不会收集它,因为该对象的引用数仍为2.实际上,本机中的ViewController具有仍然是对这种观点的参考。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM