MonoTouch アプリでこの例外が発生し、修正できないようです。私は今約6時間試していますが、運がありません。
この例外についての私の理解は、オブジェクトが MonoTouch によって参照されている (または参照されようとしている) が、ガベージ コレクションによって既に破棄されているということです。したがって、ポインターを使用して、クラスに設定していないコンストラクターを使用して、それへの参照を再度構築しようとしています。
当初、私はそのコンストラクターを追加するだけで十分だと考えていましたが、調査を行って、せいぜい一時的な包帯であることに気付きました。私が奇妙に感じているのは、私が見る限り、すべてへの参照を保持していることです。私は少し行き過ぎて、例外をキャプチャしようとするために必ずしも保持する必要がないもののメンバー変数の作成を開始しましたが、それでも何もしません。
エラーは、ViewController をロードし、新しい ViewController を NavigationController にプッシュするデリゲートをトリガーして (画面を離れて)、戻るボタンを押して別のビューに再度移動すると発生します。これは一貫して同じように発生し、この時点で常にクラッシュしますが、GC の動作方法により、必ずしも同時にクラッシュするとは限りません。
アプリはこれまでのところ非常にシンプルです。最初の画面では、ShinobiCharts を使用して 5 つの異なるチャートを読み込みます。データ ソースとデリゲートは ViewController に設定され、ViewModel が View に送信され、サブビューにグラフが追加されます。例外は、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;
}
}
最後に、ビュー:
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:
これは、チャートの 1 つのデリゲートです。エラーを処理するメソッドは必要ないため、見逃してしまいました。_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();
}
}