我在我的 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();
}
}