C# UIViewController子类(模仿UITableViewController)不';我不能被释放

C# UIViewController子类(模仿UITableViewController)不';我不能被释放,c#,ios,inheritance,memory-management,xamarin,C#,Ios,Inheritance,Memory Management,Xamarin,我有一个子类UIViewController,它模仿UITableViewController=HUDTableViewController。然后我从这个视图控制器子类(SomeViewController:HUDTableViewController)中创建子类 如果我模拟内存警告,SomeViewController不会被释放。以下是HUDTableViewController的代码: using System; using Foundation; using UIKit; namesp

我有一个子类
UIViewController
,它模仿
UITableViewController
=
HUDTableViewController
。然后我从这个视图控制器子类(
SomeViewController:HUDTableViewController
)中创建子类

如果我模拟内存警告,
SomeViewController
不会被释放。以下是HUDTableViewController的代码:

using System;

using Foundation;
using UIKit;

namespace MyApp
{
    public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable, IUIScrollViewDelegate
    {
        private UIView parentView;
        private UITableView tableView;

        public UITableView TableView
        {
            get
            {
                return this.tableView;
            }
            set
            {
                this.tableView = value;
            }
        }

        public HUDTableViewController() : base()
        {
            Initialize();
        }

        private void Initialize()
        {
            this.tableView = new UITableView();
            this.tableView.TranslatesAutoresizingMaskIntoConstraints = false;

            this.tableView.WeakDelegate = this;
            this.tableView.WeakDataSource = this;

            this.parentView = new UIView();
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            this.parentView.AddSubview(this.tableView);
            View = this.parentView;

            NSMutableDictionary viewsDictionary = new NSMutableDictionary();
            viewsDictionary["parent"] = this.parentView;
            viewsDictionary["tableView"] = this.tableView;

            this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
        }

        [Foundation.Export("numberOfSectionsInTableView:")]
        public virtual System.nint NumberOfSections(UIKit.UITableView tableView)
        {
            return 1;
        }

        public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section)
        {
            throw new NotImplementedException();
        }

        public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            throw new NotImplementedException();
        }

        [Export("tableView:estimatedHeightForRowAtIndexPath:")]
        public virtual System.nfloat EstimatedHeight(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            return UITableView.AutomaticDimension;
        }

        [Foundation.Export("tableView:didSelectRowAtIndexPath:")]
        public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
        }

        [Export("tableView:heightForRowAtIndexPath:")]
        public virtual System.nfloat GetHeightForRow(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            return 44.0f;
        }

        [Foundation.Export("tableView:heightForHeaderInSection:")]
        public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section)
        {
            return UITableView.AutomaticDimension;
        }

        [Foundation.Export("tableView:viewForHeaderInSection:")]
        public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section)
        {
            return null;
        }

        [Export("tableView:titleForHeaderInSection:")]
        public virtual string TitleForHeader(UITableView tableView, nint section)
        {
            return string.Empty;
        }

        [Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")]
        public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath)
        {
        }
    }
}
public class MasterViewContainer : UIViewController
{
    private bool hasSetupHandlersAndEvents = false;
    // ...

    public override void ViewWillAppear (bool animated)
    {
        base.ViewWillAppear (animated);

        if (!hasSetupHandlersAndEvents) {
            if (listButton != null) {
                listButton.Clicked += listButton_Clicked;
            }
            hasSetupHandlersAndEvents = true;
        }
    }

    public override void ViewWillDisappear (bool animated)
    {
        base.ViewWillDisappear (animated);

        if (hasSetupHandlersAndEvents) {
            if (listButton != null) {
                listButton.Clicked -= listButton_Clicked;
            }
            hasSetupHandlersAndEvents = false;
        }
    }

    private void listButton_Clicked(object sender, EventArgs args){
        SomeViewController viewController = new SomeViewController();
        viewController.SomeEvent += SomeEventHandler;
        NavigationController.PushViewController(viewController, false);
    }
}
protected override void Dispose(bool disposing)
{
    if(!this.disposed)
    {
        if(disposing)
        {
           this.tableView.RemoveFromSuperview();
           this.tableView.Dispose();
        }
        this.disposed = true;
    }
    base.Dispose(disposing);
}
tableView
的引用计数应为2(因为
AddSubView
和我的属性)

这是主视图控制器,它实例化了
SomeViewController

using System;

using Foundation;
using UIKit;

namespace MyApp
{
    public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable, IUIScrollViewDelegate
    {
        private UIView parentView;
        private UITableView tableView;

        public UITableView TableView
        {
            get
            {
                return this.tableView;
            }
            set
            {
                this.tableView = value;
            }
        }

        public HUDTableViewController() : base()
        {
            Initialize();
        }

        private void Initialize()
        {
            this.tableView = new UITableView();
            this.tableView.TranslatesAutoresizingMaskIntoConstraints = false;

            this.tableView.WeakDelegate = this;
            this.tableView.WeakDataSource = this;

            this.parentView = new UIView();
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            this.parentView.AddSubview(this.tableView);
            View = this.parentView;

            NSMutableDictionary viewsDictionary = new NSMutableDictionary();
            viewsDictionary["parent"] = this.parentView;
            viewsDictionary["tableView"] = this.tableView;

            this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
        }

        [Foundation.Export("numberOfSectionsInTableView:")]
        public virtual System.nint NumberOfSections(UIKit.UITableView tableView)
        {
            return 1;
        }

        public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section)
        {
            throw new NotImplementedException();
        }

        public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            throw new NotImplementedException();
        }

        [Export("tableView:estimatedHeightForRowAtIndexPath:")]
        public virtual System.nfloat EstimatedHeight(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            return UITableView.AutomaticDimension;
        }

        [Foundation.Export("tableView:didSelectRowAtIndexPath:")]
        public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
        }

        [Export("tableView:heightForRowAtIndexPath:")]
        public virtual System.nfloat GetHeightForRow(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            return 44.0f;
        }

        [Foundation.Export("tableView:heightForHeaderInSection:")]
        public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section)
        {
            return UITableView.AutomaticDimension;
        }

        [Foundation.Export("tableView:viewForHeaderInSection:")]
        public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section)
        {
            return null;
        }

        [Export("tableView:titleForHeaderInSection:")]
        public virtual string TitleForHeader(UITableView tableView, nint section)
        {
            return string.Empty;
        }

        [Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")]
        public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath)
        {
        }
    }
}
public class MasterViewContainer : UIViewController
{
    private bool hasSetupHandlersAndEvents = false;
    // ...

    public override void ViewWillAppear (bool animated)
    {
        base.ViewWillAppear (animated);

        if (!hasSetupHandlersAndEvents) {
            if (listButton != null) {
                listButton.Clicked += listButton_Clicked;
            }
            hasSetupHandlersAndEvents = true;
        }
    }

    public override void ViewWillDisappear (bool animated)
    {
        base.ViewWillDisappear (animated);

        if (hasSetupHandlersAndEvents) {
            if (listButton != null) {
                listButton.Clicked -= listButton_Clicked;
            }
            hasSetupHandlersAndEvents = false;
        }
    }

    private void listButton_Clicked(object sender, EventArgs args){
        SomeViewController viewController = new SomeViewController();
        viewController.SomeEvent += SomeEventHandler;
        NavigationController.PushViewController(viewController, false);
    }
}
protected override void Dispose(bool disposing)
{
    if(!this.disposed)
    {
        if(disposing)
        {
           this.tableView.RemoveFromSuperview();
           this.tableView.Dispose();
        }
        this.disposed = true;
    }
    base.Dispose(disposing);
}
如您所见,
SomeViewController
引用了
MasterViewContainer
,因为
SomeEventHandler

SomeViewController
如果我使用

public class SomeViewController : UITableViewController
public class SomeViewController : HUDTableViewController
,但如果我使用

public class SomeViewController : UITableViewController
public class SomeViewController : HUDTableViewController
从不调用
Dispose
方法。我没有看到一个参考周期。我必须在哪里发布一些东西?我错过了什么

尝试1:

这是我想到的唯一解决办法。我使用一个字段(类变量),在该字段中保存对
SomeViewController
的引用。在
direceivememorywarning
中,我手动释放/处置它。当我想访问该字段时,我会检查它是否已初始化。如果没有,我会在需要时初始化它

public class MasterViewContainer : UIViewController
{
    private SomeViewController viewController;

    public override void DidReceiveMemoryWarning ()
    {
        // Releases the view if it doesn't have a superview.
        base.DidReceiveMemoryWarning ();

        // Release any cached data, images, etc that aren't in use.
        if (this.viewController != null)
        {
            this.viewController.SomeEvent -= SomeEventHandler;
            this.viewController.Dispose();
            this.viewController = null;
        }
    }

    private void listButton_Clicked(object sender, EventArgs args){
        if (this.viewController == null)
        {
            this.viewController = new SomeViewController();
            this.viewController.SomeEvent += SomeEventHandler;
        }

        NavigationController.PushViewController(this.viewController, false);
    }
但这个解决方案并不完美。当视图当前在屏幕上时,也会调用dispose。所以很可能出现故障

赏金:

我想有一个解决方案,可以解释内存管理问题。为什么不发布?要发布它需要做什么改变(不做我尝试中的事情)。它的行为应该类似于
UITableViewController

尝试2:

现在,我尝试覆盖
HUDTableViewController
Dispose(bool disposing)

using System;

using Foundation;
using UIKit;

namespace MyApp
{
    public class HUDTableViewController : UIViewController, IUITableViewDataSource, IUITableViewDelegate, IDisposable, IUIScrollViewDelegate
    {
        private UIView parentView;
        private UITableView tableView;

        public UITableView TableView
        {
            get
            {
                return this.tableView;
            }
            set
            {
                this.tableView = value;
            }
        }

        public HUDTableViewController() : base()
        {
            Initialize();
        }

        private void Initialize()
        {
            this.tableView = new UITableView();
            this.tableView.TranslatesAutoresizingMaskIntoConstraints = false;

            this.tableView.WeakDelegate = this;
            this.tableView.WeakDataSource = this;

            this.parentView = new UIView();
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            this.parentView.AddSubview(this.tableView);
            View = this.parentView;

            NSMutableDictionary viewsDictionary = new NSMutableDictionary();
            viewsDictionary["parent"] = this.parentView;
            viewsDictionary["tableView"] = this.tableView;

            this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
            this.parentView.AddConstraints(NSLayoutConstraint.FromVisualFormat("V:|[tableView]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
        }

        [Foundation.Export("numberOfSectionsInTableView:")]
        public virtual System.nint NumberOfSections(UIKit.UITableView tableView)
        {
            return 1;
        }

        public virtual System.nint RowsInSection(UIKit.UITableView tableview, System.nint section)
        {
            throw new NotImplementedException();
        }

        public virtual UIKit.UITableViewCell GetCell(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            throw new NotImplementedException();
        }

        [Export("tableView:estimatedHeightForRowAtIndexPath:")]
        public virtual System.nfloat EstimatedHeight(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            return UITableView.AutomaticDimension;
        }

        [Foundation.Export("tableView:didSelectRowAtIndexPath:")]
        public virtual void RowSelected(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
        }

        [Export("tableView:heightForRowAtIndexPath:")]
        public virtual System.nfloat GetHeightForRow(UIKit.UITableView tableView, Foundation.NSIndexPath indexPath)
        {
            return 44.0f;
        }

        [Foundation.Export("tableView:heightForHeaderInSection:")]
        public virtual System.nfloat GetHeightForHeader(UIKit.UITableView tableView, System.nint section)
        {
            return UITableView.AutomaticDimension;
        }

        [Foundation.Export("tableView:viewForHeaderInSection:")]
        public virtual UIKit.UIView GetViewForHeader(UIKit.UITableView tableView, System.nint section)
        {
            return null;
        }

        [Export("tableView:titleForHeaderInSection:")]
        public virtual string TitleForHeader(UITableView tableView, nint section)
        {
            return string.Empty;
        }

        [Foundation.Export("tableView:willDisplayCell:forRowAtIndexPath:")]
        public virtual void WillDisplay(UIKit.UITableView tableView, UIKit.UITableViewCell cell, Foundation.NSIndexPath indexPath)
        {
        }
    }
}
public class MasterViewContainer : UIViewController
{
    private bool hasSetupHandlersAndEvents = false;
    // ...

    public override void ViewWillAppear (bool animated)
    {
        base.ViewWillAppear (animated);

        if (!hasSetupHandlersAndEvents) {
            if (listButton != null) {
                listButton.Clicked += listButton_Clicked;
            }
            hasSetupHandlersAndEvents = true;
        }
    }

    public override void ViewWillDisappear (bool animated)
    {
        base.ViewWillDisappear (animated);

        if (hasSetupHandlersAndEvents) {
            if (listButton != null) {
                listButton.Clicked -= listButton_Clicked;
            }
            hasSetupHandlersAndEvents = false;
        }
    }

    private void listButton_Clicked(object sender, EventArgs args){
        SomeViewController viewController = new SomeViewController();
        viewController.SomeEvent += SomeEventHandler;
        NavigationController.PushViewController(viewController, false);
    }
}
protected override void Dispose(bool disposing)
{
    if(!this.disposed)
    {
        if(disposing)
        {
           this.tableView.RemoveFromSuperview();
           this.tableView.Dispose();
        }
        this.disposed = true;
    }
    base.Dispose(disposing);
}

既不调用
HUDTableViewController
Dispose
方法,也不调用
SomeViewController
Dispose
方法。

如果希望父视图也调用相同的函数,则调用super从那里处理管理。根据安排,您不需要进行任何其他手动处理

public override void DidReceiveMemoryWarning ()
{
    // If you want the superclass to fire the function first call super first
    // and vice versa. 
    super.didReceiveMemoryWarning();
    // Releases the view if it doesn't have a superview.
    base.DidReceiveMemoryWarning ();

您需要什么
parentView
?控制器已经有一个根视图,保证在
ViewDidLoad
中创建。因此,您不用将tableView添加为其子视图,而是将其替换为您的
parentView
。原始视图可能会保留在层次结构中并引用控制器,因此后者不会被释放。我使用此
HUDTableViewController
,因为我想将加载微调器置于其中心。因此,我可以使用这个类,而无需进一步努力。对于定心,我引入了
父视图
,因为
视图
(即
UITableView
)不起作用,并且如果我尝试使用
UITableView
的父视图,我会遇到问题。我是否有一些释放引用的选项?或者您有更好的主意将视图集中在
UITableView
中。您不应该明确地实现Dispose()方法吗?@FredM:如果我有东西要处理,我可以。问题是我应该处置/释放什么?此外,在我的项目中,
Dispose()
从不自动调用。因此,我只能手动调用
Dispose()
。默认的
UITableViewController
不需要手动调用
Dispose()
。您可以尝试以下操作: