Я пытаюсь структурировать свое приложение с использованием шаблона MVVM. Поэтому у меня есть ViewModels, которые поднимают события при изменении данных, и ожидается, что пользовательский интерфейс отреагирует на эти события и обновит видимые элементы пользовательского интерфейса.Обнаружение, когда UITableViewCells полностью завершено
У меня есть производный UITableViewCell
, который инициализируется определенной ViewModel каждый раз, когда новая ячейка создается или удаляется (очень похожа на miguel's example here). Одним из основных отличий, являющимся частью инициализации, является подписка на событие ViewModel. Это создает ссылку из долгоживущего ViewModel на эту конкретную ячейку, удерживая ее в памяти на всю жизнь ViewModel. Когда ячейка повторно используется, старая подписка очищается и создается новая, созданная для новой модели ViewModel, которая работает нормально.
Однако проблема заключается в том, что нет возможности очистить последнюю подписку после того, как ячейка полностью закончена, что означает, что она хранится в памяти на протяжении всей жизни ViewModel (гораздо дольше, чем я хочу быть). «Полностью закончена» зависит от иерархии VC, но в этом случае полученный DialogViewController, содержащий TableView с пользовательскими ячейками, был выбит из стека UINavigationController
и был удален.
willMoveToSuperview
никогда не был вызван (я надеялся, что это будет с переданным «null»). removeFromSuperview
никогда не называется. Утилизация на каждую ячейку никогда не вызывается. Утилизация UITableViewController не уничтожает каждую ячейку. Устранение TableView внутри контроллера даже не уничтожает каждую ячейку.
Единственный способ, которым я могу вручную распоряжаться каждой ячейкой (и, следовательно, очищать подписки), - это перечисление ячеек вручную самостоятельно в каждом из моих производных UIViewControllers
, чего я хочу избежать.
Есть ли у кого-либо подобные проблемы, подобные этому? Я не могу первыми использовать шаблон MVVM с UITableViewCells. Является ли это ошибкой с шаблоном Dispose в базовых оболочках MonoTouch UIKit?
EDIT: Вот вырезанная версия одного из изготовленных на заказ UITableViewCells
. Примечание. Я принимаю прагматичный подход, когда я явно подписываюсь на события свойств, которые, как я знаю, могут меняться, а не полный MVVM, связывают каждое свойство с пользовательским интерфейсом. Так что мой обязательный код состоит из только стандартных подписок на события:
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 элемент: 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;
}
Спасибо Stuart! Я отредактировал свой вопрос, чтобы включить некоторый пример кода. Я думаю, что сейчас я собираюсь использовать более строгий подход к жизненному циклу ViewModel. Что касается вашего слабого подхода к мероприятиям делегатов: действуйте с осторожностью. Мы сделали это некоторое время назад, и это дополнительное усложнение, которое все разработчики должны держать в своих головах. например Подписка на эти события с помощью лямбда-подписки с закрытием очень затрудняет отслеживание ошибок, так как ничто не содержит экземпляр закрывающей копии в памяти и поэтому в какой-то момент в будущем будет GCed, эффективно отменяя ваш обработчик событий. – Tyson
Спасибо @Tyson - Я недавно был там с lambdas в реализации Messenger :) Внимание! (Вот почему эта тема была открыта 8 месяцев) – Stuart
Просто добавьте перекрестную ссылку на другие материалы WeakReference http://stackoverflow.com/ а/14734264/373321 – Stuart