ある画面から画面遷移でcontroller_Aに戻ってきた後などに、controller_Aから別のcontroller_Bにアクセスしようとしたときに、下記のようなWarningが起きました。
Warning: Attempt to present <viewController_B> on <viewController_A> which is already presenting (null)
※ 読みやすさのため、以下では viewController を VC と表記します。
このWarningが起きたあとでは、呼び出そうとしていたVC_Bは全く呼び出せず、
そのまま操作しているとアプリがクラッシュするなど悪さをしていました。
Stackoverflowなどを調べましたが、似たような現象はあっても、
直接解決してくれる記事は見つけられませんでした。
ですが、試行錯誤の末に解決法を見つけましたので、
同じような現象に困っている方への情報共有や知見保存のために記事にします。
原因は何なのか?
このWarning(警告)の直訳は、
「VC_Aにはすでに(null)が与えられている状態で、VC_Bを与えようとしていますよ」
と言っています。これはどういう意味でしょうか。
前提として、一つのVCがアクセスできるのは別の一つのVCだけです。
ですのでこれは、
「VC_Aは(null)にアクセスしている(と思い込んでいる)ので、この上さらにVC_Bにアクセスすることはできませんよ」
と言っていると解釈できます。
こうなってしまう原因はどうやら2つあります。
- 原因1. 画面遷移の前に使っていたVC_Cで、別のVC_Dにアクセスしていた
- 原因2. 理由1のアクセスを続けたまま、”戻る”などの画面遷移でVC_Aに戻ってきた
このときに、”VC_CがVC_Dにアクセスしていたまま”という情報がそのままVC_Aでも維持されてしまい、”VC_Aが(null)にアクセスしている状態”になってしまう様です。
(なぜVC_Dではなくnullなのか?という疑問は残ります汗)
具体的には私は、VC_CでsearchControllerにアクセス中にVC_Aに戻ったとき、VC_Aで新規画面の呼び出し操作ができなくなるバグに遭遇しました。
解決方法
解決方法としては、画面遷移から戻ってきたときに実行されるVC_AのviewWillApear()で、
明示的にアクセスを削除する必要があります。
VC_Aに下記のコードを追記します。
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 画面遷移で戻ってきたとき、present中のVCを削除。 self.presentedViewController?.dismiss(animated: false, completion: nil) // 以下省略〜〜 }
presentedViewController?が、今VC_AがアクセスしているVC(ここではおそらく(null))を指しています。dissmiss()でアクセスを削除しています。
これで、先程のWarningが出なくなります。
また、原因1, 2の手順通りに操作しても、VC_Bを呼び出せるようになります。
あとがき
この方法に気づくまで、まれに発生していたクラッシュの原因がわからず数ヶ月悶々としていました。同じようなことで悩んでいる皆様の助けになれましたら幸いです。
ここまでお読みいただき、ありがとうございました。
コメント