3

我在我的 MonoTouch 应用程序中遇到了这个异常,我似乎无法修复它。我已经尝试了大约 6 个小时,但我没有运气。

我对这个异常的理解是,一个对象正在被 MonoTouch 引用(或试图被引用),但垃圾收集已经处理了它。因此,它希望使用我没有在类中设置的构造函数,使用指针再次构建对它的引用。

最初我认为添加该构造函数就足够了,直到我做了一些研究并意识到它充其量只是一个临时绷带。我发现奇怪的是,据我所知,我持有对所有内容的引用。我什至有点过火了,开始为不一定需要保留的东西创建成员变量来尝试捕获异常,但仍然没有。

当我加载 ViewController,触发将新 ViewController 推送到 NavigationController 上的委托(从而离开屏幕),点击后退按钮并再次移动到另一个视图时,会发生错误。这始终以相同的方式发生,并且在这一点上总是会崩溃,尽管由于我认为 GC 的工作方式不一定在完全相同的时间发生。

到目前为止,该应用程序非常简单。第一个屏幕使用 ShinobiCharts 加载 5 个不同的图表。数据源和委托在 ViewController 中设置,并将 ViewModel 发送到视图,然后将图表添加到子视图。异常发生在 ColumnChart(继承自 ShinobiChart 的自定义类)中。异常总是会在这些控件上引发,而不是在 View 或 ViewController 上。但是,哪个图表导致异常似乎每次都是随机的。

我如何存储图表如下所示:

public class HomeViewModel
{
    public ColumnChart MeetingsChart { get; set; }
    public ColumnChart FirmDataChart { get; set; }
    public ColumnChart SystemUseChart { get; set; }
    public BarChart IllustrationsChart { get; set; }
    public PieChart TermsOfBusinessChart { get; set; }

    public ColumnChartDataSource MeetingsChartDataSource { get; set; }
    public ColumnChartDataSource SystemUseChartDataSource { get; set; }
    public StackChartDataSource FirmDataChartDataSource { get; set; }
    public BarChartDataSource IllustrationsChartDataSource { get; set; }
    public PieChartDataSource TermsOfBusinessDataSource { get; set; }

    public BarChartDataProvider TermsOfBusinessDataProvider { get; set; }

    public DashboardMeetingChartDelegate MeetingsChartDelegate { get; set; }
    public ColumnChartDelegate SystemUseChartDelegate { get; set; }
    public PieChartDelegate TermsOfBusinessDelegate { get; set; }
}

然后在控制器中实现这个类,如下所示:(注意:很多代码被剥离,因为我认为不需要它)

public class HomeController : UIViewController
{
private HomeView _homeView;
private HomeViewModel _homeViewModel;
 …..

 public HomeController()
    {
        _homeViewModel = new HomeViewModel();
    }
….

private void LoadCharts()
    {           
        _homeViewModel.MeetingsChart = LoadMeetingsChart();
        _homeViewModel.FirmDataChart = LoadFirmDataChart();
        _homeViewModel.SystemUseChart = LoadSystemUseChart();
        _homeViewModel.IllustrationsChart = LoadIllustrationsChart();
        _homeViewModel.TermsOfBusinessChart = LoadTermsOfBusinessChart();
    }

    private ColumnChart LoadMeetingsChart()
    {
        ColumnChart meetingsChart = new ColumnChart(RectangleF.Empty);
        meetingsChart.DataSource = _homeViewModel.MeetingsChartDataSource;
        meetingsChart.Delegate = _homeViewModel.MeetingsChartDelegate;
        meetingsChart.LicenseKey = LICENSE_KEY;

        return meetingsChart;
    }
}

最后,观点:

public class HomeView : UIView
{
    private HomeViewModel _homeViewModel;

    public HomeView(RectangleF frame, UINavigationController navigationController,       HomeViewModel homeViewModel)
        : base(frame)
    {
        this._homeViewModel = homeViewModel;
        this.BackgroundColor = UIColor.FromRGB(20, 20, 20);
        this.Title = "Sales 360 Dashboard";

          SetupChartBounds(UIApplication.SharedApplication.StatusBarOrientation);
    }   

 public void SetupCharts()
    {
        SetupMeetingsChartHeaderBar();
        SetupTermsOfBusinessChartHeaderBar();
        SetupIllustrationsChartHeaderBar();
        SetupSystemUserChartHeaderBar();
        SetupFirmDataChartHeaderBar();

        this.AddSubview(_homeViewModel.MeetingsChart);
        this.AddSubview(_homeViewModel.TermsOfBusinessChart);
        this.AddSubview(_homeViewModel.IllustrationsChart);
        this.AddSubview(_homeViewModel.SystemUseChart);
        this.AddSubview(_homeViewModel.FirmDataChart);
    }    
}

我真的很感激在这个问题上的任何帮助,因为我非常坚持。谢谢。

编辑1:

HomeController 是从名为 SplashController 的东西推送而来的。SplashController 的唯一目的是显示初始屏幕视图并调用 Web 服务。Web 服务是异步调用的,完成后会将视图更改为显示所有图表的主视图。

这是一些 SplashController 类:

public class SplashController : UIViewController
{
    private SplashView _splashView;
    private SplashViewModel _splashViewModel;
    private readonly string BACKGROUND_IMAGE_PATH;
    private HomeController _homeController;
            .....

    public override void LoadView()
    {
        LoadViewModel();

        _splashView = new SplashView(new RectangleF(0, 0, Dimensions.Width, Dimensions.Height), _splashViewModel);
        this.View = _splashView;
    }

// .... a number of service calls eventually leading to this

   protected void GetTermsOfBusinessAllAgentsCompleted(object sender,   GetTermsOfBusinessAllAgentsCompletedEventArgs e)
    {
        _servicesHelper.StopTimer(e.UserState as Timer);
        if (e.Error != null)
            HandleError(e.Error, "Terms of Business");
        else
        {
            _termsOfBusinessGraphData = e.Result;
            ChangeViewToHomeView();
        }
    } 

   private void ChangeViewToHomeView()
    {
        _homeController = new HomeController(_meetingsGraphData, _firmDataGraphData, _systemUseGraphData, 
                                             _illustrationsGraphData, _termsOfBusinessGraphData);

        this.NavigationController.PushViewController(_homeController, false);
    }    
}

HomeView 是在 HomeController 类中重写的 LoadView 方法中创建的,基本上如下所示:

_homeView = new HomeView(new RectangleF(0, 0, Dimensions.Width, Dimensions.Height),    this.NavigationController, _homeViewModel);
this.View = _homeView;

至于 NavigationController,问得好。这是我之前在将 NavigationController 传递给委托时所做的事情。但是,现在所有这些都在 HomeController 中完成,因此不再需要它。对不起,我的错!我现在把它拿出来并尝试重新运行应用程序,同样的事情仍然发生。请忽略这一点。

编辑2:

这是其中一张图表的代表。我错过了处理错误的方法,因为它不需要。_meetingServices.GetAgentsData 方法在该方法中调用 Web 服务,然后返回此对象中的事件:

public class DashboardMeetingChartDelegate : SChartDelegate
{
    private UINavigationController _navigationController;
    private CategoryGraph _meetingsGraphData;
    private MeetingServices _meetingServices;
    private ServicesHelper _servicesHelper;
    private int _currentIndex;

    public DashboardMeetingChartDelegate(UINavigationController navigationController, CategoryGraph meetingsGraphData)
    {
        this._navigationController = navigationController;
        this._meetingsGraphData = meetingsGraphData;

        _meetingServices = new MeetingServices();
        _servicesHelper = new ServicesHelper();
        _currentIndex = -1;
    }

    protected override void OnToggledSelection (ShinobiChart chart, SChartDataPoint dataPoint, SChartSeries series, PointF pixelPoint)
    {
        _currentIndex = dataPoint.Index;
        _meetingServices.GetAgentsData(GetAgentsCompleted);
    }

    protected void GetAgentsCompleted(object sender, GetAgentsCompletedEventArgs e)
    {
        _servicesHelper.StopTimer(e.UserState as Timer);
        if (e.Error != null)
            HandleError(e.Error);
        else
        {
            int rsmId = Convert.ToInt32(_meetingsGraphData.Data[0].SeriesDataPoints[_currentIndex].PointMetaData);
            AgentContract currentAgent = e.Result.Agents.Where(agent => agent.Id == rsmId).First();
            _navigationController.PushViewController(new MeetingController(currentAgent), true);
        }
    }

这是 MeetingController - 与另一个非常相似,只是加载的更少:

public class MeetingController : UIViewController
{
    private AgentContract _currentAgent;
    private RsmChartView _meetingView;
    private RsmChartViewModel _meetingViewModel;
    private MeetingTypeController _meetingTypeController;
    private ColumnChartDataProvider _columnChartDataProvider;

    public MeetingController(AgentContract currentAgent)
    {
        _currentAgent = currentAgent;
    }

    public override void LoadView ()
    {
        LoadColumnChartDataProvider();
        LoadViewModel();
        InitialiseView();
    }

    private void LoadColumnChartDataProvider()
    {
        _columnChartDataProvider = new ColumnChartDataProvider();
        _columnChartDataProvider.XValueList.Add(new NSString("Phone"));
        _columnChartDataProvider.XValueList.Add(new NSString("Demo"));
        _columnChartDataProvider.XValueList.Add(new NSString("Fact Finding"));

        _columnChartDataProvider.YValueList.Add(61);
        _columnChartDataProvider.YValueList.Add(22);
        _columnChartDataProvider.YValueList.Add(27);
    }

    private void LoadViewModel()
    {
        _meetingViewModel = new RsmChartViewModel();
        _meetingViewModel.Chart = LoadMeetingChart();
        _meetingViewModel.RsmContentModel = LoadRsmContentModel();
    }

    private RsmContentModel LoadRsmContentModel()
    {
        RsmContentModel model = new RsmContentModel();
        model.Name = _currentAgent.Name;

        return model;
    }

    private void InitialiseView()
    {
        _meetingView = new RsmChartView(new RectangleF(0, 0, Dimensions.Width, Dimensions.Height), _meetingViewModel);
        this.View = _meetingView;
    }

    private ColumnChart LoadMeetingChart()
    {
        ColumnChart meetingChart = new ColumnChart(new RectangleF(10, 220, Dimensions.Width - 20, 540));
        _meetingTypeController = new MeetingTypeController();
        _meetingViewModel.ChartDataSource = new ColumnChartDataSource(_columnChartDataProvider);
        _meetingViewModel.ChartDelegate = new ColumnChartDelegate(this.NavigationController, _meetingTypeController);

        meetingChart.DataSource = _meetingViewModel.ChartDataSource;
        meetingChart.Delegate = _meetingViewModel.ChartDelegate;

        return meetingChart;
    }

    public override void ViewDidLoad()
    {
        _meetingView.Load();
    }
}
4

1 回答 1

3

这种情况通常很难调试。已对 MonoTouch 进​​行了一些更改,以减少此类事件的发生。

要尝试它们,我建议您尝试 6.0.7(在 beta 通道上)并在邮件列表(或错误报告)上报告任何未解决的问题。

更多详细信息可以在发行说明中找到(直接链接)。

于 2012-12-06T13:30:29.507 回答