MVVM 패턴을 사용하여 응용 프로그램을 구조화하려고합니다. 따라서 데이터가 변경 될 때 이벤트를 발생시키는 ViewModels가 있으며 UI는 해당 이벤트에 반응하고 보이는 UI 컨트롤을 업데이트해야합니다.UITableViewCells가 완전히 끝났을 때 감지
새로운 셀이 생성되거나 대기열에서 제외 될 때마다 특정 ViewModel로 초기화되는 파생 UITableViewCell
이 있습니다 (miguel's example here과 매우 유사). 초기화의 일부인 주요 차이점 중 하나는 ViewModel의 이벤트를 구독하는 것입니다. 이렇게하면 오래 지속 된 ViewModel에서이 특정 셀에 대한 참조가 만들어지며 ViewModel의 수명 동안 메모리에 유지됩니다. 셀을 재사용하면 이전 구독이 정리되고 새 ViewModel에 새 구독이 만들어져 정상적으로 작동합니다.
그러나 문제는 셀이 완전히 완료되면 마지막 구독을 정리할 수있는 기회가없는 것입니다. 즉, ViewModel의 수명 동안 메모리에 보관됩니다 (원하는 것보다 훨씬 오래 걸림). 되려고). '완전히 완료되었습니다'는 VC 계층 구조에 따라 다르지만이 경우 사용자 지정 셀이있는 TableView가 포함 된 파생 된 DialogViewController가 UINavigationController
스택에서 팝되어 삭제되었습니다.
willMoveToSuperview
은 결코 호출되지 않습니다. ('null'이 전달되기를 기대했습니다). removeFromSuperview
은 호출되지 않습니다. 각 셀이 절대로 호출되지 않습니다. UITableViewController를 삭제해도 각 셀이 처리되지 않습니다. 컨트롤러 내에서 TableView를 삭제해도 각 셀이 처리되지 않습니다.
수동으로 각 셀을 폐기 할 수있는 유일한 방법은 수동으로 셀을 열거하여 수동으로 직접 파생 된 UIViewControllers
에서 피하고 싶은 것입니다.
이와 비슷한 문제가있는 사람이 있습니까? UITableViewCells에서 MVVM 패턴을 처음 사용하는 것은 불가능합니다. 기본 MonoTouch UIKit 래퍼에 Dispose 패턴이있는 버그입니까?
편집 : 다음은 사용자 정의 UITableViewCells
중 하나의 자르기 버전입니다. 참고 UI의 모든 속성을 전체 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 요소 : 뷰 모델을, 그래서 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;
}
감사합니다. 스튜어트! 몇 가지 예제 코드를 포함하도록 제 질문을 수정했습니다. 지금은 더 엄격한 ViewModel 라이프 사이클 접근 방식을 사용하려고합니다. 약한 위임 이벤트 접근법에 관해서는주의해서 진행하십시오. 우리는이 작업을 잠시 뒤늦게 수행했으며 모든 개발자가 머리 속에 보관해야하는 추가적인 복잡성입니다. 예 : 클로저를 사용하여 람다 구독으로 이러한 이벤트를 구독하면 메모리에 백업 클로저 인스턴스가 없으므로 버그를 추적하기가 매우 어려워지고 나중에 어떤 시점에서 GCed되어 이벤트 처리기를 무작위로 구독 취소합니다. – Tyson
Thanks @Tyson - 최근 메신저 구현에 lambdas를 사용 해왔다. :) 약혼 한주의 (스레드가 8 개월 동안 열려있는 이유) – Stuart
WeakReference stuff에 대한 상호 참조 추가 http://stackoverflow.com/ a/14734264/373321 – Stuart