Bug 15375 - Dynamically generated UI causing unexpected crashes
Summary: Dynamically generated UI causing unexpected crashes
Status: RESOLVED DUPLICATE of bug 134
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 7.0.3.x
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2013-10-13 23:07 UTC by Paul Johnson
Modified: 2013-10-16 05:38 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and 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 Links.

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.

Related Links:
Status:
RESOLVED DUPLICATE of bug 134

Description Paul Johnson 2013-10-13 23:07:58 UTC
I have a view controller which when a UITabBar is clicked generates a UIView on the fly for data entry. Such code looks like this

private void createAddTank()
        {
            float xOffset = AppDelegate.Self.ScreenX == 320 ? 0 : (AppDelegate.Self.ScreenX - 320) / 2;
            string fuel = string.Empty;
            UIView addView = new UIView(new RectangleF(xOffset, (AppDelegate.Self.ScreenY / 2) - 195, 320, 390))
            {
                BackgroundColor = UIColor.LightGray
            };
            UILabel title = new UILabel(new RectangleF(96, 20, 129, 40))
            {
                Text = StringUtils.GetString("FuelTanks.New.Tank"),
                TextAlignment = UITextAlignment.Center,
                Font = UIFont.SystemFontOfSize(24f),
                BackgroundColor = UIColor.LightGray
            };
            UILabel name = new UILabel(new RectangleF(20, 76, 88, 21))
            {
                Text = StringUtils.GetString("FuelTanks.New.Name"),
                TextAlignment = UITextAlignment.Center,
                BackgroundColor = UIColor.LightGray
            };
            UILabel capacity = new UILabel(new RectangleF(20, 110, 88, 21))
            {
                Text = StringUtils.GetString("FuelTanks.New.Capacity"),
                TextAlignment = UITextAlignment.Center,
                BackgroundColor = UIColor.LightGray
            };
            UILabel type = new UILabel(new RectangleF(20, 202, 88, 21))
            {
                Text = StringUtils.GetString("FuelTanks.New.Type"),
                TextAlignment = UITextAlignment.Center,
                BackgroundColor = UIColor.LightGray
            };
            UILabel level = new UILabel(new RectangleF(20, 287, 88, 21))
            {
                Text = StringUtils.GetString("FuelTanks.New.Level"),
                TextAlignment = UITextAlignment.Center,
                BackgroundColor = UIColor.LightGray
            };
            UILabel capUnit = new UILabel(new RectangleF(258, 110, 42, 21))
            {
                TextAlignment = UITextAlignment.Center,
                Text = AppDelegate.Self.db.getShortVolumeUnits(),
                BackgroundColor = UIColor.LightGray
            };
            UILabel lvlUnit = new UILabel(new RectangleF(258, 287, 42, 21))
            {
                TextAlignment = UITextAlignment.Center,
                Text = AppDelegate.Self.db.getShortVolumeUnits(),
                BackgroundColor = UIColor.LightGray
            };
            UIButton save = new UIButton(new RectangleF(105, 339, 46, 30));
            UIButton cancel = new UIButton(new RectangleF(193, 339, 57, 30));
            save.SetTitle(StringUtils.GetString("Common.Save"), UIControlState.Normal);
            cancel.SetTitle(StringUtils.GetString("Common.Cancel"), UIControlState.Normal);
            UITextField tankName = new UITextField(new RectangleF(116, 72, 184, 30))
            {
                ReturnKeyType = UIReturnKeyType.Done,
                ClearButtonMode = UITextFieldViewMode.Always,
                BackgroundColor = UIColor.White
            };

            tankName.ShouldReturn += delegate
            {
                tankName.ResignFirstResponder();
                return true;
            };
            UITextField capVal = new UITextField(new RectangleF(116, 106, 134, 30))
            {
                ClearButtonMode = UITextFieldViewMode.Always,
                KeyboardType = UIKeyboardType.DecimalPad,
                BackgroundColor = UIColor.White
            };
            UITextField lvlVal = new UITextField(new RectangleF(116, 283, 134, 30))
            {
                BackgroundColor = UIColor.White,
                ClearButtonMode = UITextFieldViewMode.Always,
                KeyboardType = UIKeyboardType.DecimalPad,
            };
            UIToolbar toolHigh = new UIToolbar()
            {
                BarStyle = UIBarStyle.Black,
                Translucent = true,
            };
            toolHigh.SizeToFit();
            UIBarButtonItem doneHigh = new UIBarButtonItem("Done", UIBarButtonItemStyle.Done,
                (ss, ea) =>
                {
                    if (capVal.IsFirstResponder)
                        capVal.ResignFirstResponder();
                    else
                        lvlVal.ResignFirstResponder();
                });
            toolHigh.SetItems(new UIBarButtonItem[] { doneHigh }, true);
            capVal.InputAccessoryView = lvlVal.InputAccessoryView = toolHigh;
            List<string> fuels =new List<string>()
            {
                StringUtils.GetString("FuelTanks.New.Type.Petrol"), StringUtils.GetString("FuelTanks.New.Type.Biodiesel"),
                StringUtils.GetString("FuelTanks.New.Type.Diesel"), StringUtils.GetString("FuelTanks.New.Type.Oil"),
                StringUtils.GetString("FuelTanks.New.Type.Other")
            };
            UIPickerView fuelTypes = new UIPickerView(new RectangleF(116, 132, 184, 162))
            {
                BackgroundColor = UIColor.LightGray
            };
            IList<string> iFuels = fuels;
            var pickerModel = new PickerModel(iFuels);
            fuelTypes.Model = pickerModel;
            fuel = fuels[0];
            pickerModel.PickerChanged += (object sender, PickerChangedEventArgs e) => 
            {
                fuel = e.SelectedValue;
            };
            cancel.TouchUpInside += delegate {
                addView.Dispose();
           };
            save.TouchUpInside += delegate {
                FuelTank tank = new FuelTank()
                {
                    FuelTankID = AppDelegate.Self.db.getNewTankID(),
                    CanHold = double.Parse(capVal.Text),
                    Events = new List<FuelTankEvent>(),
                    Level = double.Parse(lvlVal.Text),
                    Name = tankName.Text,
                    Type = fuel
                };

                tank.Events.Add (new FuelTankEvent 
                    { 
                        Date = DateTime.Now, 
                        EventType = "AddToTank", 
                        Volume = double.Parse(lvlVal.Text), 
                        Notes = StringUtils.GetString("FuelTanks.New.Notes")
                    });

                AppDelegate.Self.syncManager.tankAction(tank, AppDelegate.Self.db.getSubscription().Farms[farmId],"Add");
                AppDelegate.Self.db.getSubscription().Farms[farmId].FuelTanks.Add(tank);
                addView.Dispose();
           };
            addView.AddSubviews(new UIView[] {title, name, capacity, type, level, capUnit, lvlUnit, save, cancel, capVal, lvlVal, 
                fuelTypes, tankName});
            View.AddSubview(addView);
        }

The code itself works and a new UIView appears. When the UIPicker though is altered, the app crashes with the rather unhelpful error

mono-rt: Stacktrace:


mono-rt:   at <unknown> <0xffffffff>

mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x0009f, 0xffffffff>

mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38

mono-rt:   at ftrack2ios.Application.Main (string[]) [0x0000a] in /Volumes/Developer/Developer/ftrack2/iOS/ftrack2-ios/ftrack2-ios/Main.cs:18

mono-rt:   at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00050, 0xffffffff>

mono-rt: 
Native stacktrace:


mono-rt: 
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

This error also appears when adding dynamically generated UIButtons onto a scroll view like this

float y = 4;
            int t = 0;
            Console.WriteLine("crops.count = {0}", crops.Count);
            foreach (string s in crops)
            {
                UIButton btn = new UIButton(UIButtonType.Custom);
                btn.Frame = new RectangleF(new PointF(4, y), new SizeF(AppDelegate.Self.ScreenX - 8, 16));
                btn.SetTitleColor(UIColor.Blue, UIControlState.Normal);
                btn.SetTitle(s, UIControlState.Normal);
                btn.Tag = t;
                btn.TouchUpInside += (object sender, EventArgs e) => 
                {
                    UIButton but = (UIButton)sender;
                    Console.WriteLine("Button title - {0}", but.CurrentTitle);
                    Crop crop = available.SingleOrDefault(ss => 
                        ss.CropName.Substring(0, ss.CropName.IndexOf(' ')) == 
                        but.CurrentTitle.Substring(0, but.CurrentTitle.IndexOf(' ')));
                    NavigationController.PushViewController(new CurrentCropType(crop, theFarm, allFarms), true);
                };
                scrlView.AddSubview(btn);
                y += 20;
                t++;
            }

Clicking on a button causes the app to crash with the same error.

I'm not sure if this is a regression or my code

Using XS 4.1.12, Xam.iOS 7.0.2.7 (Business Edition)
Comment 1 Rolf Bjarne Kvinge [MSFT] 2013-10-16 05:38:38 UTC
This is because you need to keep a managed references to UIButtons [1], otherwise the GC will free them (and the event handler with it, causing a crash when the button is tapped.

[1] You need to keep a managed reference to all platform types you've attached an event handler to (UIButton for instance, but not if you create a UIButton subclass, such as "class MyCustomButton : UIButton {}").

*** This bug has been marked as a duplicate of bug 134 ***