UIPageViewController不会释放最后显示的对话框
我提出了一个简单的UIPageViewController,并添加了一些非常简单和愚蠢的子视图控制器。 当UIPageViewController被取消时,我将处置所有子视图控制器,当前不显示的(在ChildViewControllers中列出的)和显示的(在ViewControllers中列出的)。 没有显示的人得到释放,显示的人得不到。
我已经将其分解为一个简单的失败testing,所以我确定这不是关于子视图控制器的内容或其他一些问题。 我不知道是什么保留它。
样品:
主(呈现)
public class MasterDialog : UIPageViewController { public event EventHandler OnDialogClosed; private UIBarButtonItem _backButton; public MasterDialog() : base( UIPageViewControllerTransitionStyle.Scroll, UIPageViewControllerNavigationOrientation.Horizontal, UIPageViewControllerSpineLocation.None, 25) { _backButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel); _backButton.Clicked += Close; NavigationItem.SetLeftBarButtonItem(_backButton, false); } public override void ViewDidDisappear(bool animated) { base.ViewDidDisappear(animated); OnDialogClosed(this, EventArgs.Empty); } private void Close(object sender, EventArgs arguments) { _backButton.Clicked -= Close; NavigationController.DismissViewController(true, null); } protected override void Dispose(bool disposing) { base.Dispose(disposing); Console.WriteLine("Master disposed"); } }
主数据源
public class DataSource : UIPageViewControllerDataSource { public override UIViewController GetPreviousViewController( UIPageViewController pageViewController, UIViewController referenceViewController) { var detail = (DetailDialog)referenceViewController; if (detail.Page - 1 == 0) return null; return GetViewController(detail.Page - 1); } public override UIViewController GetNextViewController( UIPageViewController pageViewController, UIViewController referenceViewController) { var detail = (DetailDialog)referenceViewController; return GetViewController(detail.Page + 1); } public UIViewController GetViewController(int page) { return new DetailDialog(page); } }
细节(儿童)
public class DetailDialog : UITableViewController { public int Page { get; private set; } public DetailDialog(int page) : base(UITableViewStyle.Plain) { Page = page; } public override void ViewDidLoad() { base.ViewDidLoad(); Console.WriteLine("Detail init: " + Page + " / " + GetHashCode()); var label = new UILabel(); label.Text = "#" + Page; label.ContentMode = UIViewContentMode.Center; label.Frame = new System.Drawing.RectangleF(0, 100, 320, 50); label.BackgroundColor = UIColor.Green; Add(label); } protected override void Dispose(bool disposing) { base.Dispose(disposing); Console.WriteLine("Detail disposed: " + Page + " / " + GetHashCode()); } }
打开对话框(起点)
public class StartDialog : UIViewController { private DataSource _dataSource; private MasterDialog _master; public StartDialog() { Title = "WTF"; } public override void ViewDidLoad() { base.ViewDidLoad(); var button = new UIButton(UIButtonType.Custom); button.SetTitle("Open", UIControlState.Normal); button.BackgroundColor = UIColor.Green; button.Frame = new System.Drawing.RectangleF(20, 150, 280, 44); Add(button); button.TouchDown += OpenMasterDialog; } private void OpenMasterDialog(object sender, EventArgs arguments) { _dataSource = new DataSource(); _master = new MasterDialog(); _master.DataSource = _dataSource; _master.OnDialogClosed += HandleOnDialogClosed; _master.SetViewControllers( new [] { _dataSource.GetViewController(1) }, UIPageViewControllerNavigationDirection.Forward, false, null ); NavigationController.PresentViewController( new UINavigationController(_master), true, null ); } private void HandleOnDialogClosed(object sender, EventArgs e) { _dataSource.Dispose(); _dataSource = null; Console.WriteLine("Before: " + _master.ChildViewControllers.Length + "/" + _master.ViewControllers.Length + ")"); var childs = _master .ChildViewControllers.ToList() .Union(_master.ViewControllers); foreach (UIViewController child in childs) { child.RemoveFromParentViewController(); child.Dispose(); } Console.WriteLine("After: " + _master.ChildViewControllers.Length + "/" + _master.ViewControllers.Length + ")"); _master.OnDialogClosed -= HandleOnDialogClosed; _master.Dispose(); _master = null; } }
我可能会误解你的代码/意图,但在这种情况下,似乎一切都很好。 无论如何,这是我的发现…
Detail disposed: 1 / 36217954 After: 0/1)
第2行显示/1
,我认为是问题。 这是正常的,因为你正在重新渲染视图控制器,IOW代码:
_master.ViewControllers.Length
调用viewControllers
上的UIPageViewController
select器。 这将返回:“ 页面视图控制器显示的视图控制器 ”, 该视图仍然是此时的DetailDialog
(即使DetailDialog
不再显示)。
这不是Xamarin特定的,ObjC应用程序会在同一时间返回相同的(本地)实例。
这是解释 – 但它仍然没有释放,为什么?
在新的Dispose
语义下,只要本地端需要它(但没有本地引用,所以它可以本地释放,随后在pipe理端释放), Dispose
之后就会保留托pipe对象。
在这种情况下, 本地对象的生命周期还没有结束(即iOS仍然引用它),所以它在受pipe理端保持活动状态。
_master.Dispose(); _master = null;
这将删除对_master
的托pipe引用,但是同样如上所述,只要使用本地_master
实例(使用本机引用),它就不会被释放 (也不会是DetailDialog
)。
那么谁给了_master
一个参考?
NavigationController.PresentViewController( new UINavigationController(_master),
^这创build了一个UINavigationController
,只要它还活着,就有对别人的引用。
当我处理UINavigationController
(我把它放在一个字段中)时,Master *和Detail *实例从HeapShot中消失。
_nav.Dispose(); _nav = null;