[英]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 : HUDTableViewController
) SomeViewController : 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
: 现在我试图覆盖
HUDTableViewController
的Dispose(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.