特定の条件で rootViewController を差し替えるとメモリリークする件
UIApplication.shared.keyWindow?.rootViewController
で画面を差し替えたい時がありますよね?
例えばどんな時があるかとかと言いますと
- 認証画面があり signup/signin 後に画面を切り替え
- sigup/signin 後にチュートリアルの画面を表示
- signout 後に認証画面を表示
などがあるかなと思います。
タイトルの通り、とある条件を満たして rootViewController
を切り替えると差し替える前の viewController
が解放されずに残り続けてしまいます。
これは iOS8 頃から認識していた問題ではありますが、iOS10 現在になっても修正されていません。
これのタチが悪いところは今使用されているメモリのほぼ全てがリークしてしまうといったことです。 今あなたのアプリがメモリを100MB使用しているとすると、それがそのままメモリリークしてしまうのでいきなり 100MB の負債を担うことになります。
これを解放するためにはアプリを App Switcher からアプリを kill するしかありません。
なんどもやってしまうと芋づる式にメモリリークしていっちゃいます。 かなり辛いですね。
どうすればメモリリークするのか。 それは 「モーダルが表示されている状態で rootViewController を差し替える」です。
この太字のとこおがかなり重要です。 つまりは モーダルが表示されている場合 モーダルを閉じてから rootViewController を差し替えればいいといった話ですね。
簡単に試せるようにサンプルプロジェクトを作りました。
dissmissの部分をコメントアウトして試してもらえると、メモリリークすることが確認できます。
メモリリークするとき
メモリリークしないとき
signout したり画面を切り替える度にメモリリークしていて悩んでいる方は、一度確認してみるといいのではないでしょうか。
追記
そもそも
window.rootViewController
を差し替えるとうのがあまり良くないので、空のビューコントローラでいいのでそれをRootにして、それはずっと変わらないように保って、それ以下のコントローラを付け替えるようにするのがいいです。
コメントで教えてもらったのですが window を差し替えるよりも、この方がアニメーションもつけやすくていいですね。 勉強になりました。