2

I have a legacy C# class that extends UIAlertView for prompting the user to enter an IP address. It also will persist the IP address and load it as the default entry value.

The original code hacked the iOS4.x UIAlertView to add a text field and it had several layout problems. I converted the code to use the iOS5 UIAlertView's AlertViewStyle setting and everything worked fine.

I was asked to enable the Done key on the popup keyboard so that it could be a shortcut to the Connect button. I added code as follows to the class's constructor:

public AddressAlertView()
{
    AddButton("Cancel");
    AddButton("Connect");
    AlertViewStyle = UIAlertViewStyle.PlainTextInput;

    // NEW - get input text field, enable Done on the keyboard and
    // allow Done to be the same as the Connect button
    UITextField fld = GetTextField(0);
    fld.ReturnKeyType = UIReturnKeyType.Done;
    fld.ShouldReturn = (textField) =>
    {
        DismissWithClickedButtonIndex(1, true);
        return textField.ResignFirstResponder();
    };
    // *** end of new code ***

    // restore saved IP address
    string savedAddress = NSUserDefault.StandardUserDefaults.StringForKey(AddressKey);
    if (savedAddress != null)
        fld.Text = savedAddress;
}

The class gets used like so:

....
AddressAlertView addrPrompt = new AddressAlertView();
addrPrompt.Title = "IP Address";
addrPrompt.Message = "Enter address";
addrPrompt.Dismissed += (sender, e) =>
{
    if (e.ButtonIndex == 1)
    {
        // use IP address...
        ....
    }
};
addrPrompt.Show();
....

Now the problem. When running this code, the AddressAlertView shows the popup dialog correctly and everything works as before. However, if I tap Done on the keyboard, the app bombs out in UIAlertView.

I tried moving the new code to the public override void LayoutSubviews() method, but it still crashes.

Any ideas?

hypercode
  • 488
  • 2
  • 10
  • Sorry, still learning comment formatting. Figured it out. In looking at the trace dump output from MonoTouch, there was a mention of an invalid object. Instead of getting the text field as a local variable, I save a reference to it as an instance variable:`private UITextField _addressTextField = null;` I changed the code in the constructor to `_addressTextField = GetTextField(0);`. That solved the crash. The local `UITextField` variable was undoubtedly getting GC'd, causing the crash when `ShouldReturn` lambda expression was getting called. – hypercode Jan 13 '12 at 19:28
  • You should make your explanation an answer and accept your own answer to help others who look for a solution to a similar problem. This is perfectly okay and wanted on StackOverflow. – Krumelur Jan 14 '12 at 18:28

3 Answers3

1

You need to declare the AddressAlertView as a class member:

AddressAlertView addrPrompt;
public void DoSomething()
{

    addrPrompt = new AddressAlertView();
    //etc

}

The problem in this type of situations (I had many similar with UIAlertViews) is that the AddressAlertView object is GC'd and the event handler causes the crash. To make sure this is the issue, do not change anything, just remove/comment the addrPrompt.Dismissed += ... line and test it again. If it does not crash, than this is the solution.

Dimitris Tavlikos
  • 8,170
  • 1
  • 27
  • 31
  • 1
    Yeah, I discovered something similar. See my comment above. I didn't have to make my `AddressAlertView` a class member. – hypercode Jan 13 '12 at 19:35
  • The UIAlertView is one of the classes that Monotouch handles smart. You don't have to hold a class reference. MT will take care of this internally. – Krumelur Jan 13 '12 at 20:23
  • @Krumelur Is this for sure? I had lots of issues with UIAlertView a few months back. Now that you've mentioned this, I'll check again with the latest stable version. – Dimitris Tavlikos Jan 13 '12 at 22:36
  • 1
    Yep, this is sure. Read Miguel's answer here: http://stackoverflow.com/questions/7113145/what-does-it-mean-if-the-garbage-collector-is-more-aggressive-in-monotouch-4 – Krumelur Jan 14 '12 at 18:25
0

According to Apple's documentation, you should not be subclassing UIAlertView:

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html

miguel.de.icaza
  • 32,654
  • 6
  • 58
  • 76
  • Yup, I know the sage words of Apple in this matter. I inherited this code, so I had to make it work. A better way to do this class would be to encapsulate `UIAlertView` rather than inherit from it. BTW, all your work on MonoTouch rocks. – hypercode Jan 15 '12 at 04:27
0

Figured it out. In looking at the trace dump output from MonoTouch, there was a mention of an invalid object. Instead of getting the text field as a local variable, I save a reference to it as an instance variable:

private UITextField _addressTextField = null;

I changed the code in the constructor to:

_addressTextField = GetTextField(0);

Voila! That solved the crash. The local UITextField variable was undoubtedly getting GC'd, causing the crash when the ShouldReturn lambda expression was getting called.

hypercode
  • 488
  • 2
  • 10