2013-03-20 63 views
0

我有一个名为WaitTableView的UITableView的控制器。它只有一个小区,这里是UITableViewCell类的代码:Monotouch UITableviewCells永不销毁

public class TableViewWaitCell : UITableViewCell 
    { 
     public UIActivityIndicatorView activityIndicator = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray); 
     public UILabel lblLoading = new UILabel(); 

     public TableViewWaitCell(UITableViewCellStyle style, string reuseIdentifier) : base (style, reuseIdentifier) 
     { 
      this.SelectionStyle = UITableViewCellSelectionStyle.None; 
     } 

     ~TableViewWaitCell(){ 
      System.Console.WriteLine("TableViewWaitCell.~TableViewWaitCell"); 
      lblLoading = null; 
      activityIndicator = null; 
      System.GC.Collect(); 
     } 
     protected override void Dispose (bool disposing){ 
      System.Console.WriteLine("TableViewWaitCell.Dispose"); 
      lblLoading = null; 
      activityIndicator = null; 
      base.Dispose (disposing); 
      GC.Collect(); 
     } 

     public override void Draw (System.Drawing.RectangleF rect) 
     { 
      base.Draw (rect); 

      var context = UIGraphics.GetCurrentContext(); 
      var gradient = new CGGradient(
      CGColorSpace.CreateDeviceRGB(), 
       new float[] { 1f, 1f, 1f, 1f, 
           0.68f, 0.68f, 0.72f, 1f }, 
       new float[] { 0f, 1f }); 
       context.DrawLinearGradient(gradient, 
        new PointF(rect.X+rect.Width/2, rect.Y), 
        new PointF(rect.X+rect.Width/2, rect.Y+rect.Height), 
        CGGradientDrawingOptions.DrawsAfterEndLocation); 

      var activityIndicatorViewFrame = new RectangleF(rect.X + rect.Width/2-10, rect.Y+10, 20, 20); 
      this.activityIndicator .Frame = activityIndicatorViewFrame; 
      this.activityIndicator.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions; 
      this.activityIndicator.StartAnimating(); 
      this.AddSubview(this.activityIndicator); 

      var labelFrame = new RectangleF(rect.X, rect.Y+10+activityIndicatorViewFrame.Height, rect.Width, 35); 
      this.lblLoading.Frame = labelFrame; 
      this.lblLoading.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions; 
      this.lblLoading.TextColor = UIColor.Black; 
      this.lblLoading.BackgroundColor = UIColor.Clear; 
      this.lblLoading.TextAlignment = UITextAlignment.Center; 
      this.lblLoading.Text = Dictionary.GetValue("Loading"); 
      this.AddSubview(this.lblLoading); 
     } 
    } 

这里是主UIViewControllerViewWillDisappear方法:

 public override void ViewWillDisappear (bool animated) 
    { 
     Console.WriteLine("SpotlightView.ViewWillDisappear"); 
     if(this.PopoverController!=null) 
      this.PopoverController.Dismiss(true); 
     this.PopoverController = null; 
     this.tableView.RemoveFromSuperview(); 
     this.WaitTableView.RemoveFromSuperview(); 
     this.searchBar.RemoveFromSuperview(); 
     this.tableView.Source = null; 
     this.tableView.Dispose(); 
     this.tableView = null; 
     this.WaitTableView.Source = null; 
     this.WaitTableView.Dispose(); 
     this.WaitTableView = null; 
     this.searchBar.Delegate = null; 
     this.searchBar.Dispose(); 
     this.searchBar = null; 

     base.ViewWillDisappear (animated); 
    } 

我的问题是,无论析构函数也不的Dispose我的细胞被召唤了。当我运行heapshot时,TableViewWaitCell类的实例数量增长了,我浏览了我的应用程序。我不明白如何在Monotouch中管理单元生命周期,我可能做错了什么?

回答

0

问题来自哪个引用我的视图控制器的方法因此prenventing我的细胞和我的控制器的集合的事件处理程序。

2

我没有看到任何会在您分享的代码中导致此问题的东西。但是,您不会显示细胞如何构建和存储。你的对象可能被你的示例代码中没有显示的根保存。我在下面创建了一个示例,显示Dispose和正在调用的终结器。

使用模拟器可快速收集表格视图和单元格。通常在第二次按下“显示表格”按钮之后。

在设备上运行会显示不同的行为。表格和单元格不会立即收集。最简单的解释是,GC“调整”为只在需要时运行。所以如果你的应用没有使用太多的内存,所有的对象都将继续存在。

您可以执行两件事来强制GC按示例中所示运行。

showTable.TouchUpInside += delegate { 
    navController.PushViewController (new MyViewController(), true); 
    // Not a great idea to call Collect but you could to force it. 
    // GC.Collect(); 
}; 

allocate.TouchUpInside += delegate { 
    // Trigger the GC by creating a bunch of objects 
    System.Collections.Generic.List<object> list = new System.Collections.Generic.List <object>(); 
    for (int i=0; i<2048; i++) 
    { 
     list.Add (new object()); 
    } 
}; 

首先,您可以调用GC.Collect。但我不建议这样做。当你想让它运行时,GC运行得最好。 (在大多数情况下)。When is it acceptable to call GC.Collect?

第二只是继续写代码,让GC决定什么是最好的。在示例中,我添加了另一个按钮,分配一堆对象并将它们添加到列表中。因此,如果您在表格视图和主视图之间切换几次,然后按分配按钮几次,您应该看到终结器运行。

using System; 
using MonoTouch.Foundation; 
using MonoTouch.UIKit; 
using MonoTouch.CoreGraphics; 
using System.Drawing; 

namespace delete20130320 
{ 
    [Register ("AppDelegate")] 
    public partial class AppDelegate : UIApplicationDelegate 
    { 
     UIWindow window; 


     public override bool FinishedLaunching (UIApplication app, NSDictionary options) 
     { 
      window = new UIWindow (UIScreen.MainScreen.Bounds); 

      var mainView = new UIViewController(); 
      var showTable = UIButton.FromType (UIButtonType.RoundedRect); 
      showTable.Frame = new System.Drawing.RectangleF (10, 10, 150, 35); 
      showTable.SetTitle ("Show Table", UIControlState.Normal); 

      var allocate = UIButton.FromType (UIButtonType.RoundedRect); 
      allocate.Frame = new System.Drawing.RectangleF (10, 55, 150, 35); 
      allocate.SetTitle ("Allocate", UIControlState.Normal); 

      mainView.View.BackgroundColor = UIColor.White; 
      mainView.View.Add (showTable); 
      mainView.View.Add (allocate); 

      var navController = new UINavigationController (mainView); 

      showTable.TouchUpInside += delegate { 
       navController.PushViewController (new MyViewController(), true); 
       // Not a great idea to call Collect but you could to force it. 
       // GC.Collect(); 
      }; 

      allocate.TouchUpInside += delegate { 
       // Trigger the GC by creating a bunch of objects 
       System.Collections.Generic.List<object> list = new System.Collections.Generic.List <object>(); 
       for (int i=0; i<2048; i++) 
       { 
        list.Add (new object()); 
       } 
      }; 


      window.RootViewController = navController; 

      window.MakeKeyAndVisible(); 

      return true; 
     } 
    } 

    public class MyViewController : UIViewController 
    { 
     UITableView _tableView; 
     public override void ViewDidLoad() 
     { 
      base.ViewDidLoad(); 
      _tableView = new UITableView (this.View.Bounds); 
      View.Add (_tableView); 

      _tableView.DataSource = new MyDataSource(); 
     } 

     ~MyViewController() 
     { 
      // Bad practice to call other managed objects in finalizer 
      // But for sample purposes it will be ok 
      Console.WriteLine ("~MyViewController"); 
     } 

     protected override void Dispose (bool disposing) 
     { 
      // Bad practice to call other managed objects in Dispose 
      // But for sample purposes it will be ok 
      Console.WriteLine ("MyViewController.Dispose"); 
      base.Dispose (disposing); 
     } 

     class MyDataSource : UITableViewDataSource 
     { 
      public override int RowsInSection (UITableView tableView, int section) 
      { 
       return 1; 
      } 

      public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath) 
      { 
       var cell = tableView.DequeueReusableCell ("SomeUniqueString"); 
       if (cell != null) 
        return cell; 

       return new TableViewWaitCell (UITableViewCellStyle.Default, "SomeUniqueString"); 
      } 
     } 
    } 

    public class TableViewWaitCell : UITableViewCell 
    { 
     public TableViewWaitCell(UITableViewCellStyle style, string reuseIdentifier) : base (style, reuseIdentifier) 
     { 
      this.SelectionStyle = UITableViewCellSelectionStyle.None; 
      this.TextLabel.Text = "Something"; 
     } 

     ~TableViewWaitCell() 
     { 
      // Bad practice to call other managed objects in finalizer 
      // But for sample purposes it will be ok 
      System.Console.WriteLine("TableViewWaitCell.~TableViewWaitCell"); 
      // Avoid forcing the GC 
      //System.GC.Collect(); 
     } 
     protected override void Dispose (bool disposing) 
     { 
      // Bad practice to call other managed objects in Dispose 
      // But for sample purposes it will be ok 
      System.Console.WriteLine("TableViewWaitCell.Dispose"); 
      base.Dispose (disposing); 
      //GC.Collect(); 
     } 
    } 
}