UITableViewController在收到内存警告后为空

本文关键字:警告 内存 UITableViewController | 更新日期: 2023-09-27 18:29:22

我正在MonoTouch中通过子类化UITableViewControllerUITableViewSource(而不是UITableViewDataSource!!)绘制一个表视图。在我的视图控制器的构造函数中,我设置了这样的表视图源:

TableView.Source = new CustomTableViewSource();

在我的CustomTableViewSource中,我正在构建表视图的单元格。除了我在iPhone模拟器中模拟内存警告时,它的工作效果很好。如果视图被隐藏(例如,选择了选项卡栏中的其他视图控制器),当我回来时,表视图只是空白(白色背景,不再有表视图)。

但是,我在DidReceiveMemoryWarning回调中什么也没做。我还尝试在viewWillAppear中再次设置TableViewSource(如果收到内存警告),但没有成功。。。

这是垃圾收集器的问题吗?我知道GC.Collect是在收到内存警告时调用的。也许垃圾收集器只是在丢弃我的视图,而我需要再次完全显示它?

UITableViewController在收到内存警告后为空

您应该在ViewDidLoad方法中而不是在构造函数中初始化表源。该方法在加载视图控制器时调用,然后每次在内存警告后需要重新创建控制器的视图时调用。

我做了一些测试,在收到内存警告后,我得到了类似的结果。但是,我只得到一个空表视图。当我再次在ViewWillAppear中设置表源时,表中通常会填充数据。

ViewWillAppear中的实现不起作用,这让我认为该方法甚至没有被调用。如果是这样的话,我猜你的表视图在需要的时候不会被重新创建

在某些情况下,当您使用的控制器的视图不是从XIB文件创建的时,可能会发生这种情况。在这种情况下,您应该在LoadView方法中创建视图(不调用base.LoadView()):

public override void LoadView()
{
    this.View = new UITableView(UIScreen.MainScreen.ApplicationFrame); //or something similar
}

我在包含导航控制器、视图控制器等的选项卡控制器的复杂层次结构中遇到了类似的问题(未重新创建的表视图)。当我提供LoadView方法时,问题得到了解决。

我猜不透了;)

您是对的,当收到内存警告时,将调用GC.Collect()。这是来自操作系统的严重警告,MonoTouch将尝试释放自己的内存(如果可能的话)。您可以通过重写DidReceiveMemoryWarning来扩展它,这样您的应用程序也可以释放它不绝对需要的任何内存。

这种对GC的调用(和其他调用一样)意味着可以收集和释放每个未被引用的对象。现在不应该收集CustomTableViewSource实例(除非您的TableView是)。如果有疑问,您可以通过添加类型的终结器来检查这一点,例如

~CustomTableViewSource ()
{
    Console.WriteLine ("~CustomTableViewSource");
}

然而,作为CustomTableViewSource的一部分的对象可以像表的其他部分(UI)一样被收集(如果没有被引用的话)。如果看不到源代码,就无法判断。

我建议你试着找出被释放的内容,然后你应该看看需要什么来保留引用(以避免它们被收集)或需要重新创建什么(如果某些实例是故意释放的)。

总之,我的解决方案是:

public class LoginViewController : UITableViewController
{
  LoginDataSource m_loginDataSource;
  public LoginViewController(UITableViewStyle withStyle) : base(withStyle)
  {
   m_loginDataSource = new LoginDataSource(this);
  }
  public override void LoadView()
  {
    this.View = new UITableView(UIScreen.MainScreen.ApplicationFrame,  UITableViewStyle.Grouped);
  }
  public override void ViewDidLoad ()
  {
    base.ViewDidLoad ();
    TableView.Source = m_loginDataSource;
  }
}