c# - MonoTouch 异常 : Selector invoked from objective-c on a managed object of type that has been GC'ed

标签 c# ios exception xamarin.ios

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

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

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

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

到目前为止,该应用程序非常简单。第一个屏幕使用 ShinobiCharts 加载 5 个不同的图表。数据源和委托(delegate)在 ViewController 中设置,ViewModel 被发送到 View,然后将图表添加到 subview 。异常发生在 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; }
}

然后这个类在 Controller 中实现如下:(注意:很多代码被删除,因为我认为不需要它)

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;
    }
}

最后, View :

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 的唯一目的是显示启动画面 View 和调用 Web 服务。 Web 服务被异步调用,完成后会将 View 更改为显示所有图表的主视图。

这是一些 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 传递给委托(delegate)时所做的事情。但是,现在所有这些都在 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();
    }
}

最佳答案

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

要尝试它们,我建议您尝试 6.0.7(在测试版 channel 上)并在邮件列表(或错误报告)中报告任何 Unresolved 问题。

可以在发行说明 (direct link) 中找到更多详细信息。

关于c# - MonoTouch 异常 : Selector invoked from objective-c on a managed object of type that has been GC'ed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13743230/

相关文章:

c# - 如何在 LINQ 中查询 ID-名称对中的重复名称?

javascript - 使用 mp3 元数据或 HTML 在 iPhone 锁定屏幕上显示作品和轨道名称

c# - 根据导航区域将参数传递给 ViewModel 构造函数?

c# - WPF DataGrid - 如何在新添加的行上自动设置 EditMode?

ios - 将 MvvmCross 与 UIPageViewController 一起使用

ios - 如何检测被触摸的单元格的行

Java 使用 JNI 导入使用第 3 方功能的 C 中的共享库 (Python.h)

asp.net - Microsoft.EntityFrameworkCore.dll 中出现类型为 'Microsoft.EntityFrameworkCore.DbUpdateException' 的异常

C# 在调用堆栈中捕获未处理的异常

c# - 为什么 float.parse 返回错误值?