SIGSEGV error IOS - UiGestureRecognizer on UITableView

1

I have a UITableView for which I'm attaching a UIGestureRecognizer, to the ImageView with a custom cell. The recognizer works on the last row of the tableview fine, but if I try any of the cells before the last, the app crashes with the error below. I'm not entirely sure how to debug this or if in fact this is something that I should raise to Xamarin directly.

Any help is appreciated.

using System;
using System.Drawing;

using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Collections.Generic;

namespace gestures
{
public partial class gestureTest : UIViewController
{
    #region Private Variables
    private bool imageHighlighted = false;
    private bool touchStartedInside;
    #endregion


    public gestureTest () : base ("gestureTest", null)
    {
    }

    public override void DidReceiveMemoryWarning ()
    {
        // Releases the view if it doesn't have a superview.
        base.DidReceiveMemoryWarning ();

        // Release any cached data, images, etc that aren't in use.
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();



//          UIView viewGesture = new UIView ();
//
//          viewGesture.Add (tblGesture);

        fillTabele ();
        // Perform any additional setup after loading the view, typically from a nib.
    }



    protected void fillTabele( ) {



        List<WorkItem> list = new List<WorkItem>();
        list.Add (new WorkItem ("soemthing"));
        list.Add (new WorkItem ("soemthing else"));
        list.Add (new WorkItem ("soemthing other than else"));


        UITableView table = new UITableView(View.Bounds); // defaults to Plain style

        table.Source = new TableSource(list,"sptring",this);
        Add (table);

    }


    public class WorkItem  {

        public WorkItem() {}
        public WorkItem(string reftitle) {
            this.myTitle = reftitle;
        }

        private string myTitle;

        public string title
        {
            get 
            {
                return myTitle; 
            }
            set 
            { 
                myTitle = value; 
            }
        }
    }

    public class TableSource : UITableViewSource { 
        protected WorkItem[] 
        _tableItems; protected string _cellIdentifier = "TableCell"; 
        string vc; 
        UIImageView img; 
        UIViewController vController;
        UIAlertView alert; 
        UITapGestureRecognizer gesture = null; 
        //TaskViewController addTaskController;

        public TableSource(List<WorkItem> tblItemGroups, string sprint,UIViewController vCon)
        {
            this._tableItems = tblItemGroups.ToArray();
            this.vc = sprint;
            this.vController = vCon;
        }



        public override int RowsInSection(UITableView tableview, int section)
        {
            if (_tableItems != null)
            {
                return this._tableItems.Length;
            }
            else
            {
                return 0;
            }
        }
        public override UIView GetViewForHeader(UITableView tableView, int section)
        {

            return BuildSectionHeaderView(vc.ToString());
        }

        public static UIView BuildSectionHeaderView(string caption)
        {
            UIView view = new UIView(new System.Drawing.RectangleF(0, 0, 320, 20));
            UILabel label = new UILabel();
            label.BackgroundColor = UIColor.Clear;
            label.Opaque = false;
            label.TextColor = UIColor.Black;
            label.Font = UIFont.FromName("Helvetica-Bold", 16f);
            label.Frame = new System.Drawing.RectangleF(15, 0, 290, 20);
            label.Text = caption;
            view.AddSubview(label);
            return view;
        }
        public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
        {
            return 50f;
        }

        public override string TitleForHeader(UITableView tableView, int section)
        {

            return vc.ToString();
        }

        public static void ClearEmptyTableViewSpacer(UITableView oTableView)
        {
            UIView oViewSpacerClear = new UIView(new RectangleF(0, 0, oTableView.Frame.Width, 10));
            oViewSpacerClear.BackgroundColor = UIColor.Clear;
            oTableView.TableFooterView = oViewSpacerClear;

        }

        public override UITableViewCell GetCell(UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
        {

            if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
            {
                tableView.BackgroundView = null;
            }
            else
            {
                tableView.BackgroundColor = null;
            }
            WorkItem wrkitem = _tableItems[indexPath.Row];


            UITableViewCell cell = tableView.DequeueReusableCell(this._cellIdentifier);

            if (cell == null)
            {
                cell = new UITableViewCell(UITableViewCellStyle.Default, this._cellIdentifier);
            }


            NSAction action = () => {
                //alert=new UIAlertView("gesture recognized","tap me image tapped @" + gesture.LocationOfTouch (0, img).ToString (),null,"Ok","Cancel");
                alert=new UIAlertView("gesture recognized","tap me image tapped @",null,"Ok","Cancel");
                alert.Show();
            };

            cell.TextLabel.Text = wrkitem.title.ToString ();
            cell.ImageView.Image = UIImage.FromFile("images/splash-text.png");
            cell.ImageView.UserInteractionEnabled = true;
            gesture = new UITapGestureRecognizer();
            gesture.AddTarget(()=>action());
            cell.ImageView.AddGestureRecognizer(gesture);
            cell.ImageView.Frame = new RectangleF(10, 14, 5, 5);
            cell.TextLabel.Lines = 0;
            cell.TextLabel.LineBreakMode = UILineBreakMode.WordWrap;


            return cell;
        }


    }


    }
}

The 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 gestures.Application.Main (string[]) [0x00008] in /Users/xxxxxx/Projects/gestures/gestures/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.
=================================================================

!-- cell adjustments

        public override UITableViewCell GetCell(UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
        {

            if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
            {
                tableView.BackgroundView = null;
            }
            else
            {
                tableView.BackgroundColor = null;
            }
            WorkItem wrkitem = _tableItems[indexPath.Row];


            UITableViewCell cell = tableView.DequeueReusableCell(this._cellIdentifier);

            if (cell == null)
            {

                NSAction action = () => {
                    //alert=new UIAlertView("gesture recognized","tap me image tapped @" + gesture.LocationOfTouch (0, img).ToString (),null,"Ok","Cancel");
                    alert=new UIAlertView("gesture recognized","tap me image tapped @",null,"Ok","Cancel");
                    alert.Show();
                };

                cell = new UITableViewCell(UITableViewCellStyle.Default, this._cellIdentifier);

                cell.ImageView.UserInteractionEnabled = true;
                gesture = new UITapGestureRecognizer();
                gesture.AddTarget(()=>action());
                cell.ImageView.AddGestureRecognizer(gesture);
                cell.ImageView.Frame = new RectangleF(10, 14, 5, 5);
                cell.TextLabel.Lines = 0;
                cell.TextLabel.LineBreakMode = UILineBreakMode.WordWrap;

            }

            cell.TextLabel.Text = wrkitem.title.ToString ();
            cell.ImageView.Image = UIImage.FromFile("images/splash-text.png");

            return cell;
        }//


       *new error*

       2014-07-04 07:28:57.263 gestures[22619:1303] MonoTouch: Socket error while           connecting to MonoDevelop on 127.0.0.1:10000: Connection refused
  2014-07-04 07:29:16.139 gestures[22619:80b] -[__NSSetM target]: unrecognized selector sent to instance 0xe6ce030

  Unhandled Exception:
 MonoTouch.Foundation.MonoTouchException: Objective-C exception thrown.  Name:          NSInvalidArgumentException Reason: -[__NSSetM target]: unrecognized selector sent to instance       0xe6ce030
   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain  (int,string[],intptr,intptr)
   at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String      principalClassName, System.String delegateClassName) [0x0004c] in     /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38 
  at gestures.Application.Main (System.String[] args) [0x00008] in /Users/xxxxxx/Projects/gestures/gestures/Main.cs:17 
 NSInvalidArgumentException: -[__NSSetM target]: unrecognized selector sent to instance       0xe6ce030
  0   CoreFoundation                      0x0161e5e4 __exceptionPreprocess + 180
1   libobjc.A.dylib                     0x04e898b6 objc_exception_throw + 44
2   CoreFoundation                      0x016bb903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3   CoreFoundation                      0x0160e90b ___forwarding___ + 1019
4   CoreFoundation                      0x0160e4ee _CF_forwarding_prep_0 + 14
5   UIKit                               0x02ccee8c _UIGestureRecognizerSendActions + 230
6   UIKit                               0x02ccdb00 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 383
7   UIKit                               0x02ccf56d -[UIGestureRecognizer _delayedUpdateGesture] + 60
8   UIKit                               0x02cd2acd ___UIGestureRecognizerUpdate_block_invoke + 57
9   UIKit                               0x02cd2a4e _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 317
10  UIKit                               0x02cc9148 _UIGestureRecognizerUpdate + 199
11  UIKit                               0x0299519a -[UIWindow _sendGesturesForEvent:] + 1291
12  UIKit                               0x029960ba -[UIWindow sendEvent:] + 1030
13  UIKit                               0x02969e86 -[UIApplication sendEvent:] + 242
14  UIKit                               0x0295418f _UIApplicationHandleEventQueue + 11421
15  CoreFoundation                      0x015a783f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
16  CoreFoundation                      0x015a71cb __CFRunLoopDoSources0 + 235
17  CoreFoundation                      0x015c429e __CFRunLoopRun + 910
18  CoreFoundation                      0x015c3ac3 CFRunLoopRunSpecific + 467
19  CoreFoundation                      0x015c38db CFRunLoopRunInMode + 123
20  GraphicsServices                    0x060969e2 GSEventRunModal + 192
21  GraphicsServices                    0x06096809 GSEventRun + 104
22  UIKit                               0x02956d3b UIApplicationMain + 1225
23  ???                                 0x127f82ac 0x0 + 310346412
24  ???                                 0x127f713c 0x0 + 310341948
25  ???                                 0x127f6ec0 0x0 + 310341312
26  ???                                 0x127f6f4f 0x0 + 310341455
27  gestures                            0x000f655b mono_jit_runtime_invoke + 843
28  gestures                            0x00194b5f mono_runtime_invoke + 127
29  gestures                            0x0019a671 mono_runtime_exec_main + 401
30  gestures                            0x0019a434 mono_runtime_run_main + 628
31  gestures                            0x00054ffd mono_jit_exec + 93
32  gestures                            0x00235a70 main + 2784
33  gestures                            0x00003a15 start + 53

 2014-07-04 07:29:16.150 gestures[22619:80b] Unhandled managed exception: Objective-C    exception thrown.  Name: NSInvalidArgumentException Reason: -[__NSSetM target]: unrecognized     selector sent to instance 0xe6ce030 (MonoTouch.Foundation.MonoTouchException)
   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain   (int,string[],intptr,intptr)
   at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String   principalClassName, System.String delegateClassName) [0x0004c] in   /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38 
   at gestures.Application.Main (System.String[] args) [0x00008] in  /Users/seankerr/Projects/gestures/gestures/Main.cs:17 

mono-rt: Stacktrace:

  mono-rt: 
  Native stacktrace:


  mono-rt:  0   gestures                            0x000c4777 mono_handle_native_sigsegv + 327

  mono-rt:  1   gestures                            0x000cf5ba sigabrt_signal_handler + 122

  mono-rt:  2   libsystem_platform.dylib            0x05427deb _sigtramp + 43

  mono-rt:  3   ???                                 0xffffffff 0x0 + 4294967295

  mono-rt:  4   libsystem_sim_c.dylib               0x05144e12 abort + 127

 mono-rt:   5   gestures                            0x0024db33    monotouch_unhandled_exception_handler + 291

 mono-rt:   6   gestures                            0x000c4fbb   mono_invoke_unhandled_exception_hook + 91

mono-rt:    7   gestures                            0x000c3fcc mono_handle_exception_internal + 6620

mono-rt:    8   gestures                            0x000c25e9 mono_handle_exception + 41

mono-rt:    9   gestures                            0x0005cdd9 mono_x86_throw_exception + 137   

mono-rt:    10  ???                                 0x0ee30e57 0x0 + 249761367

mono-rt:    11  gestures                            0x0023d001 monotouch_exception_handler + 177

mono-rt:    12  CoreFoundation                      0x016aea1d __handleUncaughtException + 749

mono-rt:    13  libobjc.A.dylib                     0x04e89b5c _ZL15_objc_terminatev + 100

mono-rt:    14  libc++abi.dylib                     0x0535df60 _ZSt11__terminatePFvvE + 14

 mono-rt:   15  libc++abi.dylib                     0x0535db97 __cxa_rethrow + 103

mono-rt:    16  libobjc.A.dylib                     0x04e89a57 objc_exception_rethrow + 47

mono-rt:    17  CoreFoundation                      0x015c3b55 CFRunLoopRunSpecific + 613

mono-rt:    18  CoreFoundation                      0x015c38db CFRunLoopRunInMode + 123

mono-rt:    19  GraphicsServices                    0x060969e2 GSEventRunModal + 192

mono-rt:    20  GraphicsServices                    0x06096809 GSEventRun + 104

mono-rt:    21  UIKit                               0x02956d3b UIApplicationMain + 1225

mono-rt:    22  ???                                 0x127f82ac 0x0 + 310346412

mono-rt:    23  ???                                 0x127f713c 0x0 + 310341948

mono-rt:    24  ???                                 0x127f6ec0 0x0 + 310341312

mono-rt:    25  ???                                 0x127f6f4f 0x0 + 310341455

mono-rt:    26  gestures                            0x000f655b mono_jit_runtime_invoke + 843

mono-rt:    27  gestures                            0x00194b5f mono_runtime_invoke + 127

mono-rt:    28  gestures                            0x0019a671 mono_runtime_exec_main + 401

 mono-rt:   29  gestures                            0x0019a434 mono_runtime_run_main + 628

 mono-rt:   30  gestures                            0x00054ffd mono_jit_exec + 93

  mono-rt:  31  gestures                            0x00235a70 main + 2784

  mono-rt:  32  gestures                            0x00003a15 start + 53

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

Updated stack trace

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 gestures.Application.Main (string[]) [0x00008] in /Users/seankerr/Projects/gestures/gestures/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.
=================================================================

Final Update

I took @pnavk's advice and started again with the a blank project, using the code from the Xamarin website I created basic project and then added UIGestureRecognizer to the cells.

using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;

namespace gestures
{
public partial class gestureController : UIViewController
{
    public gestureController () : base ("gestureController", null)
    {
    }

    UITableView table;
    private string _caption = "caption";
    static NSString kCellIdentifier = new NSString ("MyIdentifier");
    static UIView cellView = new UIView (new RectangleF (325, 0, 320, 568));

    public override void DidReceiveMemoryWarning ()
    {
        // Releases the view if it doesn't have a superview.
        base.DidReceiveMemoryWarning ();

        // Release any cached data, images, etc that aren't in use.
    }

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        table = new UITableView (View.Bounds); // defaults to Plain style

        string[] tableItems = new string[] { "Vegetables", "Fruits", "Flower Buds", "Legumes", "Bulbs", "Tubers" };
        table.Source = new TableSource (tableItems);
        Add (table);

        cellView.BackgroundColor = UIColor.Blue;
        View.Add (cellView);

        // Perform any additional setup after loading the view, typically from a nib.
    }

    public class TableSource : UITableViewSource
    {
        string[] tableItems;
        protected string _cellIdentifier = "TableCell";

        public TableSource (string[] items)
        {
            tableItems = items;
        }

        public override int RowsInSection (UITableView tableview, int section)
        {
            return tableItems.Length;
        }

        public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
        {
            CustomVegeCell cell = tableView.DequeueReusableCell (kCellIdentifier) as CustomVegeCell;
            if (cell == null)
                cell = new CustomVegeCell (kCellIdentifier);
            cell.UpdateCell (tableItems [indexPath.Row], tableItems [indexPath.Row], UIImage.FromFile ("splash-text.png"), cellView);
            return cell;
        }

    }
}

}

ios
uitableview
xamarin.ios
xamarin
asked on Stack Overflow Jul 2, 2014 by Jimi • edited Jul 29, 2014 by Jimi

2 Answers

2

I would make the following changes to your code:

if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
{
    tableView.BackgroundView = null;
}
else
{
    tableView.BackgroundColor = null;
}

This should be moved out of GetCell and into ViewDidLoad or ViewWillAppear. The GetCell method is called repeatedly (as you scroll, or reload data) and (I could be incorrect) but this code doesn't look like it needs to be called more than once. You should also as mentioned earlier, initialize your image once in ViewDidLoad or ViewWillAppear as a global variable (ex. myImage) and just assign it, instead of loading it over and over.

Now, instead of setting the gesture recognizer each time in GetCell, you can create a custom UITableViewCell and implement the gesture recognizer on the ImageView in the AwakeFromNib method of the custom cell:

namespace gestures
{
    public partial class gestureTestCell : UITableViewCell
    {
        public static string _cellIdentifier = "gestureTestCell"; // whatever you name it in Interface Builder

        public gestureTestCell () : base ()
        {

        }

        public gestureTestCell (IntPtr handle) : base (handle)
        {

        }

        protected override void Dispose (bool disposing)
        {
            myImageView.RemoveGestureRecognizer(gesture)

            base.Dispose (disposing);
        }

        public override void AwakeFromNib ()
        {
            base.AwakeFromNib ();

            var gesture = new UITapGestureRecognizer (HandleTapGesture);
            myImageView.AddGestureRecognizer (gesture);
        }

        public override void LayoutSubviews ()
        {
            base.LayoutSubviews ();

            myImageView.UserInteractionEnabled = true;
            myImageView.Frame = new RectangleF(10, 14, 5, 5);
            myTextLabel.Lines = 0;
            myTextLabel.LineBreakMode = UILineBreakMode.WordWrap;
        }

       void HandleTapGesture (UITapGestureRecognizer gesture)
       {
        var alert = new UIAlertView("gesture recognized","tap me image tapped     @",null,"Ok","Cancel");
        alert.Show();
        }

        public override void PrepareForReuse ()
        {
            base.PrepareForReuse ();
        }


        public void SetupCell(string text, UIImage image)
        {
            myImageView.Image = image;
            myTextLabel.Text  = text;   
        }
    }
  }

Now your GetCell method can look something like:

public override UITableViewCell GetCell(UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
    gestureTestCell cell = tableView.DequeueReusableCell(gestureTestCell._cellIdentifier) ?? new gestureTestCell();

    cell.SetupCell(_tableItems[indexPath.Row].ToString(), myImage);

    return cell;
}
answered on Stack Overflow Jul 9, 2014 by pnavk • edited Jun 24, 2019 by adiga
0

That might not be the only issue but your GetCell method is problematic. Remember that UITableViewCell instances are re-used by iOS.

That means your if (cell == null) { ... } block can do a lot more than creating a new UITableViewCell instance. IOW everything that is constant/static can (and should) be done only once.

E.g.

  NSAction action = () => {
        //alert=new UIAlertView("gesture recognized","tap me image tapped @" + gesture.LocationOfTouch (0, img).ToString (),null,"Ok","Cancel");
        alert=new UIAlertView("gesture recognized","tap me image tapped @",null,"Ok","Cancel");
        alert.Show();
    };

There's no reason to create a new action each time you re-use the cell. In fact you could probably have a single one for the table view (that depends on the final code, which is likely not showing an alert).

cell.TextLabel.Text = wrkitem.title.ToString ();

The previous line cannot be reused, i.e. it's correct to execute it each time the cell is reused.

cell.ImageView.Image = UIImage.FromFile("images/splash-text.png");
cell.ImageView.UserInteractionEnabled = true;
gesture = new UITapGestureRecognizer();
gesture.AddTarget(()=>action());
cell.ImageView.AddGestureRecognizer(gesture);
cell.ImageView.Frame = new RectangleF(10, 14, 5, 5);
cell.TextLabel.Lines = 0;
cell.TextLabel.LineBreakMode = UILineBreakMode.WordWrap;

All those lines do not need to be set for each re-used cell. You could set up all of this when (and if) you create the cell.

It's not just an optimization to do so. Right now your code is adding a(nother) new additional UITapGestureRecognizer each time the cell is reused. You could run of of memory just by reusing cells.

UPDATE

Instead of:

gesture = new UITapGestureRecognizer();
gesture.AddTarget(()=>action());

do:

gesture = new UITapGestureRecognizer (action);
answered on Stack Overflow Jul 2, 2014 by poupou • edited Jun 24, 2019 by adiga

User contributions licensed under CC BY-SA 3.0