For convenience, I am using a helper class that allow to display a wait indicator without needing a variable / reference into each view. The class implement a static method public
static void ShowActivityIndicator(UIView view, bool animated, UIActivityIndicatorViewStyle style)
In this method, I am creating a DFActivity indicator and display it on the view given in parameter:
DFActivityIndicator activityIndicator = new DFActivityIndicator(view.Bounds);
view.AddSubview(activityIndicator);
activityIndicator.LabelText = NSBundle.MainBundle.LocalizedString("Loading...", "");
activityIndicator.Indicator.ActivityIndicatorViewStyle = style;
activityIndicator.Show(true);
The constructor of the method is:
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);
}
The observer is here to be able to rotate the indicator when the interface is rotated. When, the indicator is not anymore needed, I have an other static method:
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;
}
}
This is working fine, expect the Mono profiler indicates that each time I am calling ShowActivityIndicator, each instance is kept into memory even if I call HideActivityIndicator for all instances . The memory of my application is then just increasing until crashing (seems thus be a memory leak). For debugging, I tried to remove the observer on orientation changes:
NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange, this))
and… the code is not leaking anymore. Is it a MonoTouch bug or I am doing something else wrong?
Yes, I think you are not using the AddObsever/RemoveObserver methods correctly.
Here is what you are doing with the overloads you are using:
You are registering to receive notifications for status bar orientation changes, which will trigger the DeviceOrientationChange callback, if these notifications come from
this. So your callback will never be triggered (since your DFActivityIndicator never posts such a notification) but, the default center (or better, the series of objects that you mentioned in the comments) will hold a reference to the view.You are trying to remove a view instead of a notification observer. No need to explain the remaining parameters.
Here is what you should do: