简体   繁体   English

UIViewController子类(模仿UITableViewController)没有被释放

[英]UIViewController subclass (mimics UITableViewController) doesn't get released

I have subclassed UIViewController , which mimics UITableViewController == HUDTableViewController . 我有UIViewController子类,它模仿UITableViewController == HUDTableViewController Then I subclass from this subclassed view controller ( SomeViewController : HUDTableViewController ). 然后我从这个子类视图控制器( SomeViewController : HUDTableViewControllerSomeViewController : HUDTableViewController

If I simulate a memory warning, SomeViewController doesn't get released. 如果我模拟内存警告, SomeViewController不会被释放。 Here is the code of HUDTableViewController : 这是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)
        {
        }
    }
}

tableView should have a reference count of 2 (because of AddSubView and my property). tableView的引用计数应为2(因为AddSubView和我的属性)。

This is the main view controller, which instantiates SomeViewController : 这是主视图控制器,它实例化SomeViewController

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);
    }
}

As you can see SomeViewController has a reference to MasterViewContainer , because of SomeEventHandler . 正如您所看到的, SomeViewController具有对MasterViewContainer的引用,因为SomeEventHandler

SomeViewController is released if I use 如果我使用SomeViewController被释放

public class SomeViewController : UITableViewController

, but it isn't released if I use ,但如果我使用它,它不会被释放

public class SomeViewController : HUDTableViewController

The Dispose method is never called. 永远不会调用Dispose方法。 I don't see a reference cycle. 我没有看到参考周期。 Where do I have to release something? 我必须在哪里发布一些东西? What I'm missing? 我错过了什么?

Try 1: 试试1:

This is the only solution, which comes to my mind. 这是我想到的唯一解决方案。 I use a field (class variable) where I hold the reference to SomeViewController . 我使用一个字段(类变量),其中我持有SomeViewController的引用。 In DidReceiveMemoryWarning I manually release/dispose it. DidReceiveMemoryWarning我手动释放/处置它。 When I want to access the field, I check if it has been initialised before. 当我想访问该字段时,我检查它是否已经初始化。 If not I initialise it when needed. 如果不是,我会在需要时初始化它。

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);
    }

But this solution isn't perfect. 但这种解决方案并不完美。 The dispose is also called when the view is currently on screen. 当视图当前在屏幕上时,也会调用dispose。 So it is very likely to have malfunctions. 因此很可能出现故障。

Bounty: 赏金:

I'd like to have a solution, which explains the memory management issue. 我想找一个解决内存管理问题的解决方案。 Why it doesn't get released? 为什么不发布? What has to change to get it released (without doing stuff like in my try). 什么必须改变才能释放它(没有像我的尝试那样做)。 It should behave like UITableViewController . 它的行为应该像UITableViewController

Try 2: 试试2:

Now I tried to override the Dispose(bool disposing) of HUDTableViewController : 现在我试图覆盖HUDTableViewControllerDispose(bool disposing) HUDTableViewController

protected override void Dispose(bool disposing)
{
    if(!this.disposed)
    {
        if(disposing)
        {
           this.tableView.RemoveFromSuperview();
           this.tableView.Dispose();
        }
        this.disposed = true;
    }
    base.Dispose(disposing);
}

Neither this Dispose method of HUDTableViewController nor the Dispose method of SomeViewController is called. 无论这种Dispose方法HUDTableViewController也没有Dispose的方法SomeViewController被调用。

Call super if you are wanting your parent view to also call the same function handle your management from there. 如果您希望父视图也从那里调用相同的函数处理您的管理,请调用super。 Depending on the arrangement you wouldn't need to do any other manual disposing. 根据安排,您不需要进行任何其他手动处理。

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 ();

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

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