I am presenting a simple UIPageViewController and adding some really simple and stupid child view controllers to it. When the UIPageViewController gets dismissed I am disposing all child view controllers, the ones currently not displayed (listed in ChildViewControllers) and the one displayed (listed in ViewControllers). The not displayed ones get released, the displayed one gets not.
I have broken this down to a simple failing test, so I am sure it's not about the content of the child view controllers or some other issues around that. I have no idea what is retaining it.
Sample:
Master (presented)
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");
}
}
Master Data Source
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);
}
}
Detail (Child)
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());
}
}
The opening dialog (starting point)
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;
}
}