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上的UIPageViewControllerselect器。 这将返回:“ 页面视图控制器显示的视图控制器 ”, 该视图仍然是此时的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;