检测UITableViewCells何时完成

时间:2013-02-23 06:31:47

标签: ios memory-management xamarin.ios

我正在尝试使用MVVM模式构建我的应用程序。因此,我有ViewModel,它可以在数据发生变化时引发事件,并且预计UI会对这些事件作出反应并更新可见的UI控件。

我有一个派生UITableViewCell,每次创建或出列新单元时都会使用某个ViewModel进行初始化(非常类似于miguel's example here)。一个主要区别是初始化的一部分依赖于订阅ViewModel的事件。这将创建从长期存在的ViewModel到此特定单元格的引用,将其保存在内存中以查看ViewModel的生命周期。重新使用单元格时,将清除旧订阅并为新ViewModel创建一个新订阅,该工作正常。

然而问题是,一旦单元格完全完成,似乎没有机会清理最后一个订阅,这意味着它在ViewModel的生命周期内被保存在内存中(比我想要的要长得多)是)。 “完全完成”取决于VC层次结构,但在这种情况下,包含具有自定义单元格的TableView的派生DialogViewController已从UINavigationController堆栈中弹出并已被丢弃。

永远不会调用

willMoveToSuperview(我希望它会传入'null')。 永远不会调用removeFromSuperview。 永远不会调用每个单元格。 处置UITableViewController不会处理每个单元格。 在控制器中处理TableView甚至不会处理每个单元格。

我可以手动处理每个单元格(从而清理订阅)的唯一方法是在我的每个派生UIViewControllers中自己手动枚举单元格,这是我想要避免的。

有没有人有类似的麻烦?我不能成为第一个使用UVMableViewCells的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元素: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;
    }

1 个答案:

答案 0 :(得分:1)

你绝对不是第一个使用MonoTouch做Mvvm表格单元格的人。

我最近在http://slodge.blogspot.co.uk/2013/01/uitableviewcell-using-xib-editor.html

撰写了博客文章

在此之前,在NDC有一些项目(搜索“挪威航班”),并且在MonoTouch.Dialog之上建立了一个长期运行的Mvvm项目。


在MvvmCross应用程序中,我们使用绑定到ObservableCollections的表和很多其他IList类。

在这些内容中,我们通常不会遇到左生命引用的许多问题,但这是因为我们通常不鼓励人们使用长寿命的ViewModel - 我们尝试创建一个新的ViewModel数据实例。视图。但是,我确实理解这可能并不适合所有的应用程序。


当Mvx用户发现自己遇到此类问题时,我们尝试过的一些方法是:

  • 在iOS5中,我们确实使用了ViewDidUnload方法来清理绑定 - 但显然现在已经在iOS6中消失了。
  • 取决于UI呈现样式(模式,splitview,navigationcontroller,弹出窗口等),我们尝试手动检测何时“弹出”视图并使用此方法清除绑定
  • 再次取决于UI呈现样式,我们尝试使用ViewDidAppear,ViewDidDisappear事件来添加和整理绑定
  • 对于所有带数据绑定的UIKit类,我们总是使用Dispose作为额外的地方来尝试清除绑定
  • 我们已经看过使用WeakReferences(特别是从ViewModel到View),以解决UIKit对象由iOS / ObjC和MonoTouch / .Net所拥有的问题 - 这些问题特别难以解决调试。
  • 这个弱参考代码可能是下一个版本中的关键变化之一。

关于此问题的示例讨论(在Droid中而不是在触摸中)在https://github.com/slodge/MvvmCross/issues/17


对不起,我现在不能给你任何具体的建议。如果你发布一些关于如何创建和存储绑定的示例代码,我可能会提供更多帮助 - 但我无法直观地看到你正在创建的绑定。

我还有一些链接,我将在稍后添加到此答案中 - 目前在移动设备上 - 在这里添加它们太难了!


更新 - 有关WeakReference想法的更多解释,这就是我们现在在v3中针对MvvmCross的问题 - https://github.com/slodge/MvvmCross/tree/vNextDialog/Cirrious/Cirrious.MvvmCross.Binding/WeakSubscription - 基本上我的想法是使用一次性弱引用事件订阅 - 它不会将UIKit对象保留在RAM中。它还没有经过适当测试的代码。如果是,那么我会博客并更全面地谈论它!