我正在尝试使用 MVVM 模式来构建我的应用程序。因此,我有 ViewModels 在数据更改时引发事件,并且 UI 应该对这些事件做出反应并更新可见的 UI 控件。
我有一个派生UITableViewCell
,每次创建或出列新单元格时都会使用某个 ViewModel 进行初始化(与miguel 的示例非常相似)。初始化的一个主要区别在于订阅 ViewModel 的事件。这会创建一个从长期存在的 ViewModel 到这个特定单元的引用,并在 ViewModel 的生命周期内将其保存在内存中。当单元被重新使用时,旧的订阅被清理并为新的 ViewModel 创建一个新的订阅,这工作正常。
然而问题是,一旦单元格完全完成,似乎没有任何机会清理最后一个订阅,这意味着它在 ViewModel 的生命周期内保存在内存中(比我想要的要长得多)。“完全完成”取决于 VC 层次结构,但在这种情况下,包含具有自定义单元格的 TableView 的派生 DialogViewController 已从UINavigationController
堆栈中弹出并已被处置。
willMoveToSuperview
永远不会被调用(我希望它会传入'null')。
removeFromSuperview
永远不会被调用。永远不会调用每个单元格上的 Dispose。处理 UITableViewController 不会处理每个单元格。在控制器中处理 TableView 甚至不会处理每个单元格。
我可以手动处理每个单元格(并因此清理订阅)的唯一方法是自己手动枚举每个派生单元中的单元格UIViewControllers
,这是我想避免的。
有没有人遇到过类似的烦恼?我不能成为第一个使用带有 UITableViewCells 的 MVVM 模式的人。这是基本 MonoTouch UIKit 包装器中的 Dispose 模式的错误吗?
编辑:这是自定义之一的精简版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;
}