2

複雑なビュー階層を持つアプリがあり、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 のメモリ リークですか?

4

1 に答える 1

4

何が起こるかというと、ネイティブ管理の境界を越える (イベント ハンドラーを使用した) 循環依存関係があり、現在、Xamarin.iOS ランタイム/GC はこれを検出できません。

この問題の解決策は既に見つかりました。イベント ハンドラーを削除して、循環依存関係を解消します。

状況を詳しく説明しているビデオを次に示します: http://xamarin.com/evolve/2013#session-0w86u7bco2

于 2013-10-11T07:22:20.523 に答える