0

我遵循在 MonoTouch (Xamarin.iOS) 中创建 UITableView 的模式,方法是将 .Source 属性设置为嵌套 UITableViewSource 类的新实例,如下所示。另一个开发人员引起我注意的问题是,这个 UITableView 类永远不会被垃圾收集,因为嵌套类通过嵌套类的构造函数中分配的 _parentController 属性对父类的引用。相信只要嵌套类持有这个引用,父类就无法被收集。

任何人都可以确认这是否属实,并且通过以这种方式创建 UITableView 不是一个好的编程习惯,因为垃圾收集将无法释放资源?(为简洁起见,省略了一些方法和构造函数。

public partial class MyViewController : UITableViewController
{
   public override ViewDidLoad()
   {
      base.ViewDidLoad();
      this.TableView.Source = new ViewSource(this);
   }

   public class ViewSource : UITableViewSource
   {
      MyViewController _parentController;
      public ViewSource(MyViewController parentController)
      {
         _parentController = parentController;
      }
   }
}
4

1 回答 1

4

它将被释放。

原因是“Source”属性在Objective-C中是一个弱属性,这意味着那里的赋值不会在对象上调用retain,它只是保持对它的引用。

只有在 Objective-C 调用在传递的对象上保留时,才会发生阻止 GC 发生的强循环。

下面的例子展示了数据最终是如何发布的,你必须先向下钻取很多次,然后再向上钻取。

public class MyViewController : UITableViewController {
    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        this.TableView.Source = new ViewSource(this);
    }

    public class ViewSource : UITableViewSource
    {
        public override int RowsInSection (UITableView tableview, int section)
        {
            return 100;
        }

        public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
        {
            return new UITableViewCell (UITableViewCellStyle.Default, "foo");
        }

        public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
        {
            var n = AppDelegate.window.RootViewController as UINavigationController;
            n.PushViewController (new MyViewController (), true);
            GC.Collect ();
        }
        MyViewController _parentController;
        public ViewSource(MyViewController parentController)
        {
            _parentController = parentController;
        }
    }
    ~MyViewController ()
    {
        Console.WriteLine ("Disposing");
    }
}

[Register ("AppDelegate")]
public partial class AppDelegate : UIApplicationDelegate
{
    public static UIWindow window;
    public override bool FinishedLaunching (UIApplication app, NSDictionary options)
    {
        window = new UIWindow (UIScreen.MainScreen.Bounds);

        var myViewController = new MyViewController ();
        window.RootViewController = new UINavigationController (myViewController);
        window.MakeKeyAndVisible ();
        return true;
    }
}
于 2013-08-15T20:50:22.587 回答