Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
Mono organizations on
GitHub to continue tracking issues. Bugzilla will remain
available for reference in read-only mode. We will continue to work
on open Bugzilla bugs, copy them to the new locations
as needed for follow-up, and add the new items under Related
Our sincere thanks to everyone who has contributed on this bug
tracker over the years. Thanks also for your understanding as we
make these adjustments and improvements for the future.
Please create a new report on
Developer Community or GitHub with
your current version information, steps to reproduce, and relevant error
messages or log files if you are hitting an issue that looks similar to
this resolved bug and you do not yet see a matching new report.
Created attachment 843 [details]
Sample project demonstrating the issue
I am having problems with a class derived from UIButton and garbage collection. In the sample project I have created a very simple class derived from UIButton. Apart from the derivation, the class is empty. I then have a derived UIViewController which adds an instance of the button in ViewDidLoad() and wires it up to an event handler. The event handler pushes a new instance of the view controller class onto the navigation stack. I have also overridden Dispose(bool) on the view controller so that it writes to the console when it is being disposed, and then proceeds as usual.
The type of button can be easily changed by replacing the constructor on line 26 of DerivedButtonTestViewController.cs with one for the base class (UIButton). It is observing the difference between these two cases that exposes the strange behaviour.
In order to see the difference in behaviour, I run the app in the simulator, tap the horrible green button (sorry about the colour scheme), tap the back button once the new view has loaded, and then tap the green button again. When using the base UIButton class, I then get a console output saying that a view controller has been disposed. When using my custom button class, no such message arrives.
This causes memory problems in a more complex app I am writing with a similar basic structure. Am I missing something or is this a bug?
fwiw it did sounds familiar, see http://bugzilla.xamarin.com/show_bug.cgi?id=57
but that patch is still there (may be similar, but not a regression)
I have done a little more testing on this and discovered that if the derived button is removed from its superview in ViewDidDisappear, the view controller is disposed correctly.
This is an unfortunate side-effect of mixing ObjC (refcounting) and managed (garbage collection) code.
It's a complicated topic, but the issue is circular references crossing different memory management types: For user-defined types (DerivedButton for instance), MonoTouch will ensure that the object is not freed unless the native refcount reaches 1 (which is the reference managed code has, and at this point MonoTouch knows that nobody else has a reference to the object). For this sample, DerivedButton will have a refcount of 2 (one managed reference, and one from DerivedButtonTestViewController.View) - so it will not be freed. For DerivedButton to be freed, DerivedButtonTestViewController.View has to be freed (thus releasing its reference to it), and for that to happen DerivedButtonTestViewController has to be freed (thus releasing its reference to the View). But DerivedButtonTestViewController will not be freed, because DerivedButton has a (managed) reference to it (due to this line: "button.TouchUpInside += this.OnButtonTapped" - if you change OnButtonTapped to be a static method, thus breaking the cycle, you'll see that the controller is freed).
Unfortunately we've determined that it's pretty much impossible for MonoTouch to resolve this scenario, help is needed from the developer (and that help is called Dispose - if you Dispose the controller when you're done with it, the link between the controller -> view -> button).