2013-06-14 8 views
5

Guardando Advanced Memory Management da Mark Probst e Rodrigo Kumpera, ho imparato nuove tecniche come la creazione di profili Mono GC e l'utilizzo di WeakReference.Come posso risolvere il ciclo del GC causato da un gestore di eventi lambda?

Ma io ancora non capisco come a “riparare” il Puzzle 2 da 28 ':

public class CustomButton : UIButton { 
    public CustomButton() { } 
} 

public class Puzzle2Controller : UIViewController 
{ 
    public override void ViewDidLoad() 
    { 
     var button = new CustomButton(); 
     View.Add (button); 
     button.TouchUpInside += (sender, e) => 
      this.RemoveFromParentViewController(); 
    } 
} 

Il controller contiene un ref al tasto che contiene un ref al gestore di eventi che contiene un ref al controller.

Un modo per interrompere il ciclo sarebbe annullare il pulsante. Un altro modo è quello di staccare il gestore (ma dovremmo abbandonare l'utilizzo di lamdas).

Ci sono altri/più eleganti/modi per interrompere il ciclo? Possiamo in qualche modo attaccare WeakReference qui?

Grazie.

Modifica: In questo caso, il pulsante non è nemmeno un campo. Ma c'è ancora un ciclo, non c'è? È nella sottoview di Controller's View. Dobbiamo eliminarli? Non ho capito bene.

risposta

6

I cicli di solito non sono un problema in un ambiente raccolto dalla spazzatura - Devo assumere dalla domanda che questo è in qualche modo diverso in monotouch? Modifica: no, la mia ipotesi qui rimane valida - alle 7:50 nel video a cui ci si collega dimostra un ciclo che viene scartato dallo "sweep".

I cicli possono di solito essere abbandonati per l'intera vendita, non appena l'intero ciclo diventa irraggiungibile. Questo sarebbe un problema in un sistema conteggio di riferimento .

Tuttavia! Per quanto riguarda la tua domanda - il pulsante (una volta aggiunto) è a conoscenza del controller? in tal caso, si potrebbe arrivare da sender:

button.TouchUpInside += (sender, e) => 
      ((UIButton)sender).Parent.RemoveFromParentViewController(); 

Questo lambda ora non implica una variabile catturato, e non comporta un contesto di acquisizione; non contiene alcun riferimento al controller, e in realtà la maggior parte dei compilatori renderanno un singolo gestore statico piuttosto che un gestore per l'utilizzo, quindi è anche più efficiente in termini di creazioni delegate.


Re contesto di MonoTouch specificamente, allora sì, avresti bisogno di usare WeakReference<T>:

var controller = new WeakReference<Puzzle2Controller>(this); 
button.TouchUpInside += (sender, e) => { 
    var parent = controller.Object; 
    if(parent != null) parent.RemoveFromParentViewController(); 
}; 
+0

Ciao, grazie per la risposta. Questo certamente sarebbe un'opzione, ma sfortunatamente 'UIView' non ha riferimenti ai loro controllori. Se la mia comprensione è corretta, i cicli in MonoTouch * sono * un problema perché gli oggetti ObjC nativi sotto il cofano usano il conteggio dei riferimenti. (Vedi 21:30) –

+0

@DanAbramov in tal caso, vedere la modifica –

+0

Grazie! Questo ha assolutamente senso. –

Problemi correlati