Xamarin.ios 为什么MonoTouch不垃圾收集我的自定义UIButton,除非我调用button.RemoveFromSuperview()?

Xamarin.ios 为什么MonoTouch不垃圾收集我的自定义UIButton,除非我调用button.RemoveFromSuperview()?,xamarin.ios,Xamarin.ios,似乎有东西引用了我的自定义按钮,MyButton(它继承自UIButton),导致它不会被垃圾收集,除非我将其从superview中删除。这反过来会导致它所在的视图控制器也无法最终确定和收集 在我的示例中,我有一个自定义按钮,但在视图控制器上也有一个标准的ui按钮,它不需要从superview中删除即可收集。有什么区别?看起来很像我 请参阅此代码。为了举例说明,删除了不相关的行。关于示例,需要注意的一些事项: -MyButton相当空。只是一个构造函数,没有其他被重写的内容 -想象一下MyVie

似乎有东西引用了我的自定义按钮,
MyButton
(它继承自
UIButton
),导致它不会被垃圾收集,除非我将其从superview中删除。这反过来会导致它所在的视图控制器也无法最终确定和收集

在我的示例中,我有一个自定义按钮,但在视图控制器上也有一个标准的
ui按钮
,它不需要从superview中删除即可收集。有什么区别?看起来很像我

请参阅此代码。为了举例说明,删除了不相关的行。关于示例,需要注意的一些事项:

-
MyButton
相当空。只是一个构造函数,没有其他被重写的内容

-想象一下
MyViewController
UINavigationController

-
LoadView()
只需创建按钮,为每个按钮连接一个事件并将其添加到视图中

-触摸
\u按钮
会将另一个
MyViewController
推至导航控制器

-当在
viewdide()中将视图控制器弹出导航控制器时,我正在进行一些参考清理。

-在
CleanUpRefs()
中,您将看到我必须从superview中删除
\u myButton
,以便对所有对象进行垃圾收集<代码>\另一方面,不需要删除按钮

-我希望在从导航控制器弹出时收集整个MyViewController,包括所有子视图,但注释掉
\u myButton。RemoveFromSuperview()
会阻止这种情况发生

public class MyViewController : UIViewController
{
   private UIButton _button;
   private MyButton _myButton;
   private MyViewController _nextController;

   public override void LoadView()
   {
      base.LoadView();

      _button = UIButton.FromType(UIButtonType.RoundedRect);
      _button.TouchUpInside += PushNewController;
      View.AddSubview(_button);

      _myButton = new MyButton();
      _myButton.TouchUpInside += MyButtonTouched;
      View.AddSubview(_myButton);
   }

   private void PushNewController(object sender, EventArgs e)
   {
      _nextController = new MyViewController();
      NavigationController.PushViewController(_nextController, true);
   }

   private void MyButtonTouched(object sender, EventArgs e)
   {
      Console.WriteLine("MyButton touched");
   }

   public void CleanUpRefs()
   {
      //_button.RemoveFromSuperview();
      _myButton.RemoveFromSuperview();
      // remove reference from hooking up event handler
      _button.TouchUpInside -= PushNewController;
      _myButton.TouchUpInside -= MyButtonTouched;
      _button = null;
      _myButton = null;
   }

   public override void ViewDidAppear(bool animated)
   {
      base.ViewDidAppear(animated);

      if(_nextController != null)
      {
         _nextController.CleanUpRefs();
         _nextController = null;
      }
   }
}
MyButton不是一个直接的UIButton,因为它是继承的,这似乎有点不同。但话说回来,为什么调用
RemoveFromSuperview()
会删除对它的额外引用计数,特别是当有一个类似于它的UIButton不需要删除时

(我为非常糟糕的布局道歉,stackoverflow似乎在代码段上方的项目符号布局上有问题)


更新:我向MonoTouch团队提交了一份错误报告。如果您想运行示例项目,可以从那里下载它

在这种情况下不进行垃圾收集的原因只是MonoTouch中的一个bug

即将发布的MonoTouch版本将对此进行修复。如果您赶时间,可以将/Developer/MonoTouch/usr/lib/mono/2.1/MonoTouch.dll替换为我放在这里的副本:

我会做一个备份,以防我在“正在进行的工作”库中出错