I am presenting a UIViewController
modally and that view contains various UITextFields
. I've overriden the modal views InputAccessoryView
so that it shows a simple view, with one button that will ResignFirstResponder
from every UITextField
, thus dismissing the keyboard.
Recently I've been really cracking down on memory related issues so all my controllers now have a destructor. I've noticed that whenever the keyboard is shown with this overriden InputAccessoryView
whenever the Modal View is dismissed the destructor will not be called. Does this mean that the UIViewController
is not being destroyed? Am I incorrectly displaying the InputAccessoryView?
The InputAccessoryView
code is as follows:
bool accessoryViewInit = false;
UIView accessoryView = new UIView(new RectangleF(0,0,320,30));
public override UIView InputAccessoryView
{
get
{
if (!accessoryViewInit)
{
accessoryView.BackgroundColor = UIColor.FromRGBA(0.0f, 0.0f, 0.f, 0.5f);
UIButton dismiss = new UIButton(new RectangleF(50,1, 200, 28));
dismiss.BackgroundColor = UIColor.Blue;
dismiss.SetTitle("Close Keyboard", UIControlState.Normal);
dismiss.TouchUpInside += delegate(object sender, EventArgs e) {
field1.ResignFirstResponder();
field2.ResignFirstResponder();
field3.ResignFirstResponder();
};
accessoryView.AddSubview(dismiss);
}
return accessoryView;
}
}
I have a feeling that is due to the fact I'm assigning a delegate to the TouchUpInside
event for the button, is it keeping a reference to this, thus stopping the whole controller from being destroyed?
I've created a sample project which can be found at https://github.com/lukewhitt/InputAccessoryView-test
To recreate the problem: Run app, Present modal view by touching big red button. Now, if you dismiss the view without showing the keyboard, the destructor will be called. If you make on the UITextField
s first responder (showing the keyboard and the InputAccessoryView
) then dismiss the modal controller, the destructor won't be called.
EDIT
It would appear this is a bug in Monotouch that will be fixed in an up-coming release. In order to get around the problem, it seems you can't use anonymous delegates when assigning to events. So the dismiss.TouchUpInside
would become:
public override UIView InputAccessoryView {
// code before
dismiss.TouchUpInside += HandleDismissTouch;
// rest of code
}
private void HandleDismissTouch (object sender, EventArgs e)
{
field1.ResignFirstResponder();
field2.ResignFirstResponder();
field3.ResignFirstResponder();
}
then in the code that dismisses the modal controller, I've added the following:
if (dismiss != null)
{
dismiss.TouchUpInside -= HandleDismissTouch;
dismiss.Dispose();
dismiss = null;
}
which causes the destructor to be called!