簡體   English   中英

UIViewController子類(模仿UITableViewController)沒有被釋放

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

我有UIViewController子類,它模仿UITableViewController == HUDTableViewController 然后我從這個子類視圖控制器( SomeViewController : HUDTableViewControllerSomeViewController : 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)
        {
        }
    }
}

tableView的引用計數應為2(因為AddSubView和我的屬性)。

這是主視圖控制器,它實例化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);
    }
}

正如您所看到的, SomeViewController具有對MasterViewContainer的引用,因為SomeEventHandler

如果我使用SomeViewController被釋放

public class SomeViewController : UITableViewController

,但如果我使用它,它不會被釋放

public class SomeViewController : HUDTableViewController

永遠不會調用Dispose方法。 我沒有看到參考周期。 我必須在哪里發布一些東西? 我錯過了什么?

試試1:

這是我想到的唯一解決方案。 我使用一個字段(類變量),其中我持有SomeViewController的引用。 DidReceiveMemoryWarning我手動釋放/處置它。 當我想訪問該字段時,我檢查它是否已經初始化。 如果不是,我會在需要時初始化它。

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:

現在我試圖覆蓋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);
}

無論這種Dispose方法HUDTableViewController也沒有Dispose的方法SomeViewController被調用。

如果您希望父視圖也從那里調用相同的函數處理您的管理,請調用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 ();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM