Note: I've created a simple project—you can see how switching types between
UIButton
andCustomButton
in storyboard changes GC behavior.
I'm trying to get my head wrapped around MonoTouch garbage collector.
The issue is similar to the one fixed in MT 4.0, however with inherited types.
To illustrate it, consider two view controllers, parent and child.
Child's view contains a single UIButton
that writes to console on tap.
Controller's Dispose
method throws an exception so it's hard to miss.
Here goes child view controller:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
sayHiButton.TouchUpInside += (sender, e) =>
SayHi();
}
}
void SayHi()
{
Console.WriteLine("Hi");
}
protected override void Dispose (bool disposing)
{
throw new Exception("Hey! I've just been collected.");
base.Dispose (disposing);
}
Parent view controller just presents child controller and sets a timer to dismiss it and run GC:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var child = (ChildViewController)Storyboard.InstantiateViewController("ChildViewController");
NSTimer.CreateScheduledTimer(2, () => {
DismissViewController(false, null);
GC.Collect();
});
PresentViewController(child, false, null);
}
If you run this code, it predictably crashes inside ChildViewController.Dispose()
called from its finalizer because child controller has been garbage collected. Cool.
Now open the storyboard and change button type to CustomButton
. MonoDevelop will generate a simple UIButton
subclass:
[Register ("CustomButton")]
public partial class CustomButton : UIButton
{
public CoolButton (IntPtr handle) : base (handle)
{
}
void ReleaseDesignerOutlets()
{
}
}
Somehow changing the button type to CustomButton
is enough to trick garbage collector into thinking child controller is not yet eligible for collection.
How is that so?