tes*_*ing 6 c# inheritance memory-management ios xamarin
我有子类UIViewController
,模仿UITableViewController
== HUDTableViewController
.然后我从这个子类视图controller(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)
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
你可以看到SomeViewController
有一个参考MasterViewContainer
,因为SomeEventHandler
.
SomeViewController
如果我使用,就会被释放
public class SomeViewController : UITableViewController
Run Code Online (Sandbox Code Playgroud)
,但如果我使用它,它不会被释放
public class SomeViewController : HUDTableViewController
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
但这种解决方案并不完美.当视图当前在屏幕上时,也会调用dispose.因此很可能出现故障.
赏金:
我想找一个解决内存管理问题的解决方案.为什么不发布?什么必须改变才能释放它(没有像我的尝试那样做).它应该表现得像UITableViewController
.
试试2:
现在,我试图重写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);
}
Run Code Online (Sandbox Code Playgroud)
既不调用这种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 ();
Run Code Online (Sandbox Code Playgroud)