Утечка памяти с объектом, инициализированным статическим методом и использующим NSNotificationCenter - PullRequest
1 голос
/ 02 апреля 2012

Для удобства я использую вспомогательный класс, который позволяет отображать индикатор ожидания без необходимости использования переменной / ссылки в каждом представлении. Класс реализует статический метод 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 profiler указывает, что каждый раз, когда я звоню ShowActivityIndicator, каждый экземпляр сохраняется в памяти, даже если я вызываю HideActivityIndicator для всех экземпляров. Память моего приложения просто увеличивается до тех пор, пока не произойдет сбой (кажется, таким образом, утечка памяти). Для отладки я попытался удалить наблюдателя при изменении ориентации: NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange, this)) и ... код больше не течет. Это ошибка MonoTouch или я делаю что-то еще не так?

1 Ответ

3 голосов
/ 02 апреля 2012

Да, я думаю, вы неправильно используете методы AddObsever / RemoveObserver.

Вот что вы делаете с перегрузками, которые вы используете:

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

Вы регистрируетесь наполучать уведомления об изменениях ориентации строки состояния, которые будут вызывать обратный вызов DeviceOrientationChange, , если эти уведомления приходят от this.Таким образом, ваш обратный вызов никогда не сработает (поскольку ваш 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);
...