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 {
/开发者_JAVA技巧/ 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!
I think you're facing a bug in MT which will be fixed in MT 4. Looks like events handlers may prevent releasing controllers:
UIView events and garbage collection
Unfortunately, Geoff has not replied to the follow-up posters question which implications this has and if using anonymous delegates for events is an issue pre MT4.
I think a valid solution for now would be to manually Dispose().
精彩评论