Grid crashes app (still) - (Monotouch)


#1

Unfortunately we still have big problems using your grid - we explained the issue in another topic - You explained the problem due to managed-side object and a common problem with MonoTouch - we don’t agree with that “solution”.

We have now created a very simple sample show the problem - this sample is working perfect with other controls like the UITableView - but using a Simple Class implementation of ShinobiGrid crashes the app.

Looking forward to a solution

using System;
using System.Drawing;

using MonoTouch.Foundation;
using MonoTouch.UIKit;

using ShinobiGrids ;

namespace ShinobiTest
{
    public partial class ShinobiTestViewController : UIViewController
    {
        private UIButton m_cButton;
        private UIView m_cView;

//          private   SampleGrid   m_cGrid  =  null_;_
        private ShinobiGrid m_cGrid = null;
        private SimpleGridDelegate m_cGridDelegate = null;
        private SimpleGridDataSource m_cGridDataSource = null;

        public ShinobiTestViewController () : base (“ShinobiTestViewController”, null)
        {
        }
        
        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            m_cButton = UIButton.FromType(UIButtonType.InfoDark );
            m_cButton.TouchDown += (sender, e) => 
            {

                if (m_cGrid == null) {

//                      using   SampleGrid   will   chrase   the   App_._
//                      m_cGrid  =  new   SampleGrid_(new   RectangleF0 0 ,   m_cView . Frame . Width m_cView . Frame . Height ));_
                    m_cGrid = new ShinobiGrid(new RectangleF( 0, 0,  m_cView.Frame.Width, m_cView.Frame.Height ));
                    m_cGridDataSource = new SimpleGridDataSource();
                    m_cGridDelegate = new SimpleGridDelegate();

                    m_cGrid.DataSource = m_cGridDataSource;
                    m_cGrid.Delegate = m_cGridDelegate;
                    m_cView.AddSubview ( m_cGrid );
                }
                else {
                    m_cGrid.RemoveFromSuperview();
                    m_cGrid = null;
                    m_cGridDataSource = null;
                    m_cGridDelegate = null;
                }
            };
            this.View.AddSubview (m_cButton);

            m_cView = new UIView( new RectangleF( 50, 50, 400, 400 ));
            m_cView.BackgroundColor = UIColor.Red;

            this.View.AddSubview (m_cView);
        }
    }

    public class SampleGrid : ShinobiGrid
    {
        public SampleGrid ( RectangleF frame ) : base (frame)
        {
        }
    }
    
    public class SimpleGridDelegate : SGridDelegate 
    {
        public SimpleGridDelegate ()
        {
            
        }
    }
    
    public class SimpleGridDataSource : SGridDataSource
    {
        private const string kReuseIdentifier = “MyCell”;
        
        public SimpleGridDataSource( )
        {
        }
        
        protected override uint GetNumberOfRows(ShinobiGrid grid, int sectionIndex)
        {
            return (uint) 100;
        }
        
        protected override uint GetNumberOfCols(ShinobiGrid grid)
        {
            return (uint) 10;
        }
        
        protected override SGridCell GetCell (ShinobiGrid grid, SGridCoord gridCoord)
        {
            SGridAutoCell cell = grid.DequeueReusableCell (kReuseIdentifier) as SGridAutoCell;        
            if (cell == null)
                cell = new SGridAutoCell (kReuseIdentifier);
            
            cell.TextField.Text = gridCoord.RowIndex.ToString () + ‘,’ + gridCoord.Column.ToString ();
            
            return cell;
        }
        
        [Export (“conformsToProtocol:”)]
        public override bool ConformsToProtocol (IntPtr protocol)
        {
            return base.ConformsToProtocol(protocol);
        }
    }
}


#2

Hi,

Thanks for sending this code - it allowed me to replicate the issue. There are 2 issues, one in your code, one in our MonoTouch bindings. The problem starts when the grid is disposed on the managed side (by the GC). This eventually calls dealloc on the native side, which causes the native delegate property to be set to null. This property has a monotouch binding, and your grid is subclassed, so MT decides to pass control back to the managed side. However the original managed object is no longer present, and so MT creates a new one, using a constructor you haven’t got, and need to add:

public SampleGrid ( IntPtr handle ) : base (handle)

{

}

This gets you past the initial crash, and is often a useful trick when you subclass bound classes. The next problem is that the bindings do not allow us to set the managed Delegate property to null, and so it crashes a little further down the line with an ArgumentNullException. We will be fixing this in the next release but for now there is a (rather ugly) workaround, which is to explicitly Dispose the grid, catching and swallowing the ArgumentNullException, as follows:

else {

m_cGrid.RemoveFromSuperview();

try {

m_cGrid.Dispose();

}

catch (ArgumentNullException) {}

m_cGrid = null;

}

I’d recommend you revisit this workaround when the next version of ShinobiGrids is released, though.

Regards,

Robin Sillem

Lead Developer

ShinobiControls


#3

Hi,

Thanks, your workaround is working.