MVVMパターンを使用してアプリケーションを構造化しようとしています。そのため、データが変更されたときにイベントを発生させるViewModelがあり、UIはそれらのイベントに反応して、表示されているUIコントロールを更新することが期待されています。
UITableViewCell
新しいセルが作成またはデキューされるたびに特定のViewModelで初期化される派生物があります(ここでのmiguelの例と非常によく似ています)。初期化の一部である主な違いの1つは、ViewModelのイベントをサブスクライブすることに依存しています。これにより、長期間有効なViewModelからこの特定のセルへの参照が作成され、ViewModelの存続期間中はメモリに保持されます。セルが再利用されると、古いサブスクリプションがクリーンアップされ、新しいViewModelに新しいサブスクリプションが作成されます。これは正常に機能します。
ただし、問題は、セルが完全に終了すると最後のサブスクリプションをクリーンアップする機会がないように見えることです。つまり、セルはViewModelの存続期間中(私が望むよりもはるかに長く)メモリに保持されます。「完全に終了」はVC階層によって異なりますが、この場合、カスタムセルを含むTableViewを含む派生DialogViewControllerがUINavigationController
スタックからポップされ、破棄されています。
willMoveToSuperview
呼び出されることはありません(「null」が渡されることを期待していました)。
removeFromSuperview
呼び出されることはありません。各セルの廃棄は呼び出されません。UITableViewControllerを破棄しても、各セルは破棄されません。コントローラ内でTableViewを破棄しても、各セルは破棄されません。
各セルを手動で破棄する(したがってサブスクリプションをクリーンアップする)ことができる唯一の方法は、派生した各セルでセルを手動で列挙するUIViewControllers
ことです。これは避けたいことです。
誰かがこのような同様の問題を抱えていますか?UITableViewCellsでMVVMパターンを最初に使用することはできません。これは、ベースのMonoTouch UIKitラッパーのDisposeパターンのバグですか?
編集:これはカスタムの1つの縮小版ですUITableViewCells
。変更される可能性があることがわかっているプロパティのイベントを明示的にサブスクライブする実用的なアプローチを採用していることに注意してください。完全なMVVMがすべてのプロパティをUIにバインドするわけではありません。したがって、私のバインディングコードは、標準のイベントサブスクリプションのみで構成されています。
public class MyCustomCell : UITableViewCell
{
private InvoiceViewModel currentViewModel;
private readonly UILabel label1;
private readonly UILabel label2;
public MyCustomCell(NSString reuseId)
: base(UITableViewCellStyle.Default, reuseId)
{
Accessory = UITableViewCellAccessory.DisclosureIndicator;
SelectedBackgroundView = new UIView()
{
BackgroundColor = UIColor.FromRGB(235,235,235),
};
label1 = new UILabel();
ContentView.Add(label1);
// The rest of the UI setup...
}
public void Update(MyViewModel viewModel)
{
if ( currentViewModel == viewModel )
return;
if ( currentViewModel != null )
{
// Cleanup old bindings.
currentViewModel.UnacknowledgedRemindersChanged -= HandleNotificationsChanged;
}
currentViewModel = viewModel;
if ( viewModel != null )
{
viewModel.UnacknowledgedRemindersChanged += HandleNotificationsChanged;
label1.Text = viewModel.SomeProperty;
// Update the rest of the UI with the current view model.
}
}
private void HandleNotificationsChanged()
{
// Event can fire on background thread.
BeginInvokeOnMainThread(() =>
{
// Relevant UI updates go here.
});
}
protected override void Dispose(bool disposing)
{
// Unsubscribes from ViewModel events.
Update(null);
base.Dispose(disposing);
}
}
そして、派生したMT.D要素クラスには1:1のelement:viewmodelがあるため、GetCell
メソッドは次のようになります。
public override UITableViewCell GetCell (UITableView tv)
{
var cell = (MyCustomCell) tv.DequeueReusableCell(key);
if (cell == null)
cell = new MyCustomCell(key);
cell.Update(viewModel);
return cell;
}