simple but unusal!

LPKLPK USUniversity

Guys I have a problem with GetHeaderSection of UITableView. I have a custom view in the Header with a button inside. When I try to click the button, crash occurs ( Is my element GC collected ? or how can I resolve it )

`public override UIView GetViewForHeader (UITableView tableView, int section)
{
UIView view = new UIView ();

        UIButton addButton = new UIButton (UIButtonType.ContactAdd);

        addButton.Frame=new RectangleF(250, 0, 100, 40);
        addButton.TouchUpInside += (object sender, EventArgs e) => {
            new UIAlertView ("Row Selected", "test", null, "OK", null).Show ();
        };
        view.AddSubview (addButton);
        view.Frame = new RectangleF (0, 0, 400, 40);

        return view;`

Please suggest.. addButton.TouchUpInside never works. Hopefully it is GC'd. How can I resolve this ? any work around ?

Posts

  • JohnHJohnH ✭✭✭✭✭ GBMember ✭✭✭✭✭

    You could try moving the addButton variable upto a class field, if its declared at the class level it won't get collected until the instance of that class is collected. I don't know if this is your problem, but its quick to check.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod
    edited February 2014

    I received this explanation of how the GC works in Xamarin.iOS from Miguel last year, and it is relevant to your situation:

    There are two classes of NSObjects in our runtime.

    Plain wrappers to the underlying Objective-C object, and subclasses.

    Now, it is important to keep all objects referenced by either one alive, so what we do is that we mirror in the managed world any references done to new objects.

    For example:

    a = new UIView ();

    a.SomePropertyReferencingAnObject = new UIView ();

    We keep a reference to that, so that both are kept alive.

    Now, this is not a problem as long as you keep "a" alive, it will keep everything alive. But if "a" is not referenced, they become fair game to be removed from the managed side. This is in general not a problem.

    Now, we have an extra feature for any subclasses that you create by hand. When you subclass, we provide a retain/release method which will ensure that even if objects go out of scope in C# land, the object will be kept alive with a GCHandle as long as unmanaged keeps a reference.

    I just said a second ago "in general not a problem". The problem happens with APIs like UITableView when you return cells that are not kept track on managed code, and when those cells are pure Objective-C cells that you have attached some code to. This means that the state is gone, and you get bugs.

    The easy fix is simple: for UITableViewCells, instead of creating plain cells, create a subclass of UITableViewCell, and use that, it will trigger the extra protection that circumvents the problem.

    The problem in your case is very similar, but for a header view. So the solution is this (warning: I didn't actually test this, but it should work in theory):

    private class CustomButton : UIButton
    {
        public CustomButton (UIButtonType type) : base (type)
        {
        }
    }
    
    public override UIView GetViewForHeader (UITableView tableView, int section)
    {
        UIView view = new UIView ();
    
        var addButton = new CustomButton (UIButtonType.ContactAdd);
    
        addButton.Frame=new RectangleF(250, 0, 100, 40);
        addButton.TouchUpInside += (object sender, EventArgs e) => {
            new UIAlertView ("Row Selected", "test", null, "OK", null).Show ();
        };
        view.AddSubview (addButton);
        view.Frame = new RectangleF (0, 0, 400, 40);
    
        return view;
    }
    
  • DaveHuntDaveHunt ✭✭✭✭✭ USMember ✭✭✭✭✭

    I think you meant:

    var addButton = new CustomButton (UIButtonType.ContactAdd);
    
  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I did! I fixed it. Thanks.

  • LPKLPK USUniversity

    did not work for me. I created a custom class

  • AlexeyStrakhAlexeyStrakh USUniversity

    In your example, does button animate on touch?

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I don't know what you mean by "animate". It's a normal button. It does whatever a normal button does.

  • In my testing, if my constructor tried to specify the button type, TouchUpInside caused a crash. This was true even if the type was set to UIButtonType.Custom.

    If I used a constructor that set the frame (and ignored the type), the TouchUpInside worked as expected.

    private class CustomButton : UIButton {
        // With this constructor, TouchUpInside in a UITableViewHeader works as expected.
        public CustomButton (RectangleF frame) : base (frame) {
        }
    
        // This constructor causes TouchUpInside in a UITableViewHeader to crash.
        public CustomButton (UIButtonType buttonType) : base (buttonType) {
        }
    }
    
    public override UIView GetViewForHeader (UITableView tableView, int section) {
        UIView view = new UIView () {
            BackgroundColor = UIColor.Clear
        }
    
        RectangleF buttonFrame1 = new RectangleF (0, 0, 100, 100);
        RectangleF buttonFrame2 = new RectangleF (150, 0, 100, 100);
    
        CustomButton button1 = new CustomButton (buttonFrame1);
    
        button1.BackgroundColor = UIColor.Red;
        button1.TouchUpInside += delegate {
        };
    
        view.AddSubview (button1);
    
        CustomButton button2 = new CustomButton (UIButtonType.Custom);
    
        button2.BackgroundColor = UIColor.Green;
        button2.Frame = buttonFrame2;
        button2.TouchUpInside += delegate {
        };
    
        view.AddSubview (button2);
    
        return view;
    }
    
    
    Crash info:
    mono-rt: Stacktrace:
    mono-rt:   at <unknown> <0xffffffff>
    mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x000a6, 0xffffffff>
    mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:39
    mono-rt:   at ImplantTracking.Application.Main (string[]) [0x00008] in /Users/louisa/Dev/[project name]/Main.cs:17
    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.
    =================================================================
    
    Line 17 in Main.cs is the typical
    UIApplication.Main (args, null, "AppDelegate");
    
  • My testing showed that if my constructor tried to specify the button type, TouchUpInside caused a crash. This was true even if the type was set to UIButtonType.Custom.

    If I used a constructor that set the frame (and ignored the type), the TouchUpInside worked as expected.

    private class CustomButton : UIButton {
        // With this constructor, TouchUpInside in a UITableViewHeader works as expected.
        public CustomButton (RectangleF frame) : base (frame) {
        }
    
        // This constructor causes TouchUpInside in a UITableViewHeader to CRASH.
        public CustomButton (UIButtonType buttonType) : base (buttonType) {
        }
    }
    
    public override UIView GetViewForHeader (UITableView tableView, int section) {
        UIView view = new UIView () {
            BackgroundColor = UIColor.Clear
        };
    
        RectangleF buttonFrame1 = new RectangleF (0, 0, 100, 100);
        RectangleF buttonFrame2 = new RectangleF (150, 0, 100, 100);
    
        CustomButton button1 = new CustomButton (buttonFrame1);
    
        button1.BackgroundColor = UIColor.Red;
        button1.TouchUpInside += delegate {
        };
    
        view.AddSubview (button1);
    
        CustomButton button2 = new CustomButton (UIButtonType.Custom);
    
        button2.BackgroundColor = UIColor.Green;
        button2.Frame = buttonFrame2;
        button2.TouchUpInside += delegate {
        };
    
        view.AddSubview (button2);
    
        return view;
    }
    
    
    Crash info:
    mono-rt: Stacktrace:
    mono-rt:   at <unknown> <0xffffffff>
    mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x000a6, 0xffffffff>
    mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:39
    mono-rt:   at ImplantTracking.Application.Main (string[]) [0x00008] in /Users/louisa/Dev/[project name]/Main.cs:17
    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.
    =================================================================
    
    Line 17 in Main.cs is the typical
    UIApplication.Main (args, null, "AppDelegate");
    
  • In my testing, if my constructor tried to specify the button type, TouchUpInside caused a crash. This was true even if the type was set to UIButtonType.Custom.

    If I used a constructor that set the frame (and ignored the type), the TouchUpInside worked as expected.

    private class CustomButton : UIButton {
        // With this constructor, TouchUpInside in a UITableViewHeader works as expected.
        public CustomButton (RectangleF frame) : base (frame) {
        }
    
        // This constructor causes TouchUpInside in a UITableViewHeader to crash.
        public CustomButton (UIButtonType buttonType) : base (buttonType) {
        }
    }
    
    public override UIView GetViewForHeader (UITableView tableView, int section) {
        UIView view = new UIView () {
            BackgroundColor = UIColor.Clear
        }
    
        RectangleF buttonFrame1 = new RectangleF (0, 0, 100, 100);
        RectangleF buttonFrame2 = new RectangleF (150, 0, 100, 100);
    
        CustomButton button1 = new CustomButton (buttonFrame1);
    
        button1.BackgroundColor = UIColor.Red;
        button1.TouchUpInside += delegate {
        };
    
        view.AddSubview (button1);
    
        CustomButton button2 = new CustomButton (UIButtonType.Custom);
    
        button2.BackgroundColor = UIColor.Green;
        button2.Frame = buttonFrame2;
        button2.TouchUpInside += delegate {
        };
    
        view.AddSubview (button2);
    
        return view;
    }
    
    
    Crash info:
    mono-rt: Stacktrace:
    mono-rt:   at <unknown> <0xffffffff>
    mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x000a6, 0xffffffff>
    mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:39
    mono-rt:   at ImplantTracking.Application.Main (string[]) [0x00008] in /Users/louisa/Dev/[project name]/Main.cs:17
    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.
    =================================================================
    
    Line 17 in Main.cs is the typical
    UIApplication.Main (args, null, "AppDelegate");
    
  • My testing showed that if my constructor tried to specify the button type, TouchUpInside caused a crash. This was true even if the type was set to UIButtonType.Custom.

    If I used a constructor that set the frame (and ignored the type), the TouchUpInside worked as expected.

    private class CustomButton : UIButton {
        // With this constructor, TouchUpInside in a UITableViewHeader works as expected.
        public CustomButton (RectangleF frame) : base (frame) {
        }
    
        // This constructor causes TouchUpInside in a UITableViewHeader to CRASH.
        public CustomButton (UIButtonType buttonType) : base (buttonType) {
        }
    }
    
    public override UIView GetViewForHeader (UITableView tableView, int section) {
        UIView view = new UIView () {
            BackgroundColor = UIColor.Clear
        };
    
        RectangleF buttonFrame1 = new RectangleF (0, 0, 100, 100);
        RectangleF buttonFrame2 = new RectangleF (150, 0, 100, 100);
    
        CustomButton button1 = new CustomButton (buttonFrame1);
    
        button1.BackgroundColor = UIColor.Red;
        button1.TouchUpInside += delegate {
        };
    
        view.AddSubview (button1);
    
        CustomButton button2 = new CustomButton (UIButtonType.Custom);
    
        button2.BackgroundColor = UIColor.Green;
        button2.Frame = buttonFrame2;
        button2.TouchUpInside += delegate {
        };
    
        view.AddSubview (button2);
    
        return view;
    }
    
    
    Crash info:
    mono-rt: Stacktrace:
    mono-rt:   at <unknown> <0xffffffff>
    mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x000a6, 0xffffffff>
    mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:39
    mono-rt:   at ImplantTracking.Application.Main (string[]) [0x00008] in /Users/louisa/Dev/[project name]/Main.cs:17
    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.
    =================================================================
    
    Line 17 in Main.cs is the typical
    UIApplication.Main (args, null, "AppDelegate");
    
Sign In or Register to comment.