2012-04-02 5 views
1

Der Einfachheit halber verwende ich eine Hilfsklasse, die es ermöglicht, eine Warteanzeige anzuzeigen, ohne dass in jeder Ansicht eine Variable/Referenz benötigt wird. Die Klasse implementieren eine statische Methode publicSpeicherverlust mit in einer statischen Methode initialisiertem Objekt und Verwendung von NSNotificationCenter

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

Bei dieser Methode Ich bin ein DFActivity Indikatoren erstellen und auf der im Parameter angegebenen Ansicht anzuzeigen:

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

Der Konstruktor der Methode ist:

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); 

} 

Der Beobachter ist hier in der Lage, den Indikator zu drehen, wenn die Schnittstelle gedreht wird. Wenn der Indikator nicht mehr benötigt, ich habe eine andere statische Methode:

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; 
    } 
} 

Dies funktioniert gut, erwartet, dass die Mono-Profiler zeigen an, dass jedes Mal, wenn ich ShowActivityIndicator nenne, jede Instanz in dem Speicher gehalten wird, selbst wenn ich Rufen Sie HideActivityIndicator für alle Instanzen auf. Die Erinnerung an meine Anwendung steigt dann nur noch bis zum Absturz (scheint also ein Speicherleck zu sein). Zum Debuggen habe ich versucht, den Beobachter bei Orientierungsänderungen zu entfernen: NSNotificationCenter.DefaultCenter.AddObserver(UIApplication.DidChangeStatusBarOrientationNotification, DeviceOrientationDidChange, this)) und ... der Code leckt nicht mehr. Ist es ein MonoTouch Bug oder mache ich etwas anderes falsch?

+0

Meine Vermutung ist, ich nicht das Recht addObserver/removeObserver Methode verwende. – nicolas

+1

Sie sagen also, dass das Entfernen des Beobachters in HideActivityIndicator nicht funktioniert, aber das Entfernen des Beobachters bei Orientierungsänderungen funktioniert? Der HeapShot-Profiler kann Ihnen auch mitteilen, welches Objekt den DFActivityIndicator am Leben erhält, wenn Sie das Kontrollkästchen "Inverse Referenzen" aktivieren. –

+0

Nein, wenn ich die Zeilen 'AddObserver' und 'RemoveObserver' kommentiere, scheint es, dass es keine Lecks mehr gibt. Die Referenz, die 'DFActivityIndicator' am Leben zu halten scheint, ist' System.Action ', gehalten von' MonoTouch.Foundation.InternalNSNotificationHandler', gehalten von 'System.Collection.Generic.List ', gehalten von 'MonoTouch .Foundation.NSNotifikationszentrum'. – nicolas

Antwort

3

Ja, ich denke, Sie verwenden die AddObsever/RemoveObserver Methoden nicht korrekt. Hier

ist, was Sie mit den Überlastungen tun Sie verwenden:

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

Sie registrieren Benachrichtigungen für Statusleiste Orientierungsänderungen zu erhalten, die den DeviceOrientationChange Rückruf auslösen, wenn diese Meldungen kommen austhis. Ihr Callback wird also nie ausgelöst (da Ihr DFActivityIndicator niemals eine solche Benachrichtigung veröffentlicht), aber das Standardzentrum (oder besser die Reihe von Objekten, die Sie in den Kommentaren erwähnt haben) enthält einen Verweis auf die Ansicht.

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

Sie versuchen, eine Ansicht anstelle eines Benachrichtigungsbeobachters zu entfernen. Keine Notwendigkeit, die restlichen Parameter zu erklären.

Hier ist, was Sie tun sollten:

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

Vielen Dank! Es hat mein Problem behoben! – nicolas