2013-06-14 10 views
5

Mark ProbstとRodrigo KumperaのAdvanced Memory Managementを見て、私はMono GCをプロファイリングし、WeakReferenceを使うなどの新しい技術を学びました。ラムダイベントハンドラに起因するGCサイクルを修正するにはどうすればよいですか?

しかし、私はまだ28分からのパズル2「を修正」する方法を理解していない:

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

コントローラはへのREFを保持しているイベントハンドラに参照を保持しているボタンに参照を保持していますコントローラ。

サイクルを中断する1つの方法は、ボタンを無効にすることです。 もう1つの方法は、ハンドラをデタッチすることです(ただし、lamdasを使用しないでください)。

他の/よりエレガントな/サイクルを壊す方法はありますか?どういうわけかWeakReferenceをここに貼り付けることはできますか?

ありがとうございました。

編集:この場合、ボタンはフィールドでもありません。しかし、まだサイクルはありますか?それはコントローラのビューのサブビューにあります。私たちはそれらをクリアする必要がありますか?よくわかりません。

答えて

6

サイクルは、ガベージコレクション環境では通常ではありません。これはモノトックでは何とか違うと思いますか?編集:いいえ、私の前提はここでも有効です。ビデオへのリンクの7:50に「掃引」によって捨てられるサイクルを示しています。

サイクル数通常は、サイクル全体が到達不能になるとすぐに、完全に売り切れになることがあります。これは、参照カウントシステムでは問題になります。

ただし、あなたの質問に関して - ボタンは(一度追加された)コントローラーについて知っていますか?もしそうなら、あなたはsenderそこから得ることができる:

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

このラムダを今取り込んだ変数を必要としない、とキャプチャコンテキストを必要としません。コントローラーへの参照は保持されません。実際、ほとんどのコンパイラーは、1つの使用法ごとにハンドラーではなく1つの静的ハンドラーを作成するため、デリゲート作成の面でも効率的です。

MonoTouchでの文脈再

具体的には、[はい、あなたはWeakReference<T>を使用する必要があるだろう:

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

こんにちは、返信いただきありがとうございます。これは確かにオプションですが、残念ながら 'UIView'はコントローラを参照していません。私の理解が正しいならば、MonoTouch *のサイクルは問題になります。なぜなら、ネイティブのObjCオブジェクトは参照カウントを使用するからです。 (21:30を参照してください) –

+0

@ DanAbramovこの場合、編集 –

+0

ありがとう!これは完全に理にかなっています。 –

関連する問題