複雑なビュー階層を持つアプリがあり、1 つのビュー コントローラー (RootVC と呼びましょう) が他の多くのビュー コントローラーにつながる可能性があります。RootVCをポップしたら、完全に解放したい。私は参照をフィールドや他の場所に保存せず、それで十分だと信じていました。しかし最近、Xamarin の Heap Shot を確認したところ、「すべてのオブジェクト」セクションで、RootVC の多くのインスタンスがメモリに残っていることがわかりました。
たとえば、次のようになります。
sealed class VC1 : UIViewController
{
...
private void OpenVC2()
{
var vc2 = new VC2();
NavigationController.PushViewController(vc2, true);
}
}
sealed class VC2 : UIViewController
{
private UIButton button;
public override ViewDidLoad()
{
...
button = new UIButton(frame);
button.TouchUpInside += HandleButtonTouch;
...
}
private void HandleButtonTouch(object sender, EventArgs e)
{
NavigationController.PopViewControllerAnimated(true):
}
}
Heap Shot のスクリーンショットへのリンクは次のとおりです (評判が悪いため画像として投稿できません) - http://imgur.com/a/3MYBr#1
VC2 を使用している場合、最初のスクリーンショットのようなものが表示されます。
VC2 と VC1 をポップすると、ヒープ ショットは 2 番目の画像のようになります。
いくつかの VC2 が表示された後、3 番目のスクリーンショットのようになります。
そして、それらは破棄されたりファイナライズされたりすることはなく、最後まで残ります。ルート経由でも到達できません。メモリには限りがあり、これらすべての VC2 がメモリ内にあると、メモリの警告やアプリの終了が簡単に発生するため、これは受け入れられません。
しかし、ビューのボタンイベントをサブスクライブ/サブスクライブ解除すると、次のように表示/非表示になります:
sealed class VC2 : UIViewController
{
private UIButton button;
public override ViewDidLoad()
{
...
button = new UIButton(frame);
...
}
public override void ViewWillAppear(bool animated)
{
...
button.TouchUpInside += HandleButtonTouch;
}
public override void ViewDidDisappear(bool animated)
{
...
button.TouchUpInside -= HandleButtonTouch;
}
private void HandleButtonTouch(object sender, EventArgs e)
{
NavigationController.PopViewControllerAnimated(true):
}
}
この場合、VC2 (そのすべてのビューなどを含む) は、消えるときに適切に破棄されます。~VC2() が呼び出され、すべての VC2 がヒープ ショットに表示されなくなります。
では、ここで質問です。私が間違っていることは何ですか?上記のような制御イベントを購読/購読解除する必要がありますか? それとも、Xamarin.iOS のメモリ リークですか?