内存泄漏,对象在静态方法中初始化,并使用NSNotificationCenter

本文关键字:初始化 NSNotificationCenter 静态方法 泄漏 对象 内存 | 更新日期: 2023-09-27 18:29:50

为了方便起见,我使用了一个助手类,它允许显示等待指示符,而不需要对每个视图进行变量/引用。该类实现了一个静态方法public

static void ShowActivityIndicator(UIView view, bool animated,  UIActivityIndicatorViewStyle style)

在这种方法中,我创建了一个DFActivity指示器,并将其显示在参数中给出的视图上

DFActivityIndicator activityIndicator = new DFActivityIndicator(view.Bounds);
view.AddSubview(activityIndicator);
activityIndicator.LabelText = NSBundle.MainBundle.LocalizedString("Loading...", "");
activityIndicator.Indicator.ActivityIndicatorViewStyle = style;
activityIndicator.Show(true);

该方法的构造函数是:

public DFActivityIndicator(RectangleF frame) : base(frame)
{      
  Indicator = new UIActivityIndicatorView(UIActivityIndicatorViewStyle.Gray);
  this.AddSubview(Indicator);
  Indicator.StartAnimating();
  Indicator.Frame = new RectangleF(0.0f, 0.0f, 20.0f, 20.0f);
  Indicator.StartAnimating();
  //...
  Label = new UILabel(Bounds);
  RotationTransform = CGAffineTransform.MakeIdentity();
  NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange, this);
}

观察者在此能够在界面旋转时旋转指示器。当,指示器不再需要时,我有另一个静态方法:

 public static bool HideActivityIndicator(UIView view, bool animated)
{
  UIView viewToRemove = null;
  foreach(UIView v in view.Subviews)
  {
    if (v is DFActivityIndicator)
    {
      viewToRemove = v;
    }
  }
  if (viewToRemove != null)
  {
    DFActivityIndicator activityIndicator = viewToRemove as DFActivityIndicator;
    NSNotificationCenter.DefaultCenter.RemoveObserver(activityIndicator, UIApplication.DidChangeStatusBarOrientationNotification, null);
    activityIndicator.RemoveFromSuperview();
    activityIndicator.Dispose();
    activityIndicator = null;
    return true;
  }
  else
  {
    return false;
  }
}

这很好,除了Mono探查器指示每次我调用ShowActivityIndicator时,即使我为所有实例调用HideActivityIndicator,每个实例也会保留在内存中。我的应用程序的内存一直在增加,直到崩溃(因此似乎是内存泄漏)。为了进行调试,我尝试删除方向更改时的观察者:NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange, this))和代码不再泄漏。是MonoTouch错误还是我做错了什么?

内存泄漏,对象在静态方法中初始化,并使用NSNotificationCenter

是的,我认为您没有正确使用AddObsever/RemoveObserver方法。

以下是您对正在使用的过载所做的操作:

NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange, this);

您正在注册以接收状态栏方向更改的通知,如果这些通知来自this,则会触发DeviceOrientationChange回调。因此,您的回调永远不会被触发(因为您的DFActivityIndicator从未发布过这样的通知),但默认的中心(或者更好的是,您在注释中提到的一系列对象)将包含对视图的引用。

NSNotificationCenter.DefaultCenter.RemoveObserver(activityIndicator, UIApplication.DidChangeStatusBarOrientationNotification, null);

您正试图删除一个视图,而不是一个通知观察器。无需解释其余参数。

以下是您应该做的:

//To add the observer:
NSObject observerObject;
//..
this.observerObject = NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange)
//..
//To remove the observer:
NSNotificationCenter.DefaultCenter.RemoveObserver(this.observerObject);