SwiftUI の画面を開くと落ちる:EXC_BAD_ACCESS の原因は、ビューの型が深すぎて「スタックを使い切る」ことだった

SwiftUI のアプリで、特定の画面を実機で開くと EXC_BAD_ACCESS で落ちました。原因は、1つの body に詰め込みすぎてビューの型が深くなり、型の情報を組み立てるだけでメインスレッドのスタックを使い切ることでした。2つのアプリで同じことが起きた記録と、直し方、再現のしかたを書きます。

1つの body に詰め込んだ画面を、独立した部品に分けて直す流れの札

SwiftUI の画面を実機で開いた時だけ EXC_BAD_ACCESS で落ちる場合、原因は「1つの body に詰め込みすぎて、ビューの型が深くなり、型の情報を組み立てるだけでメインスレッドのスタックを使い切ること」かもしれません。私たちは、録音のアプリ(TalkLens)と、不動産の業務アプリ(Kaitori Base)の2つで、同じことが起きました。直し方は、画面を独立した struct の部品に分けることでした。

特定の画面を開くと、実機でだけアプリが落ちる。コードを見ても、おかしなところが見つからない。そんな時の、原因と直し方の記録です。落ちた画面の名前や、中のデータは書きません。

症状:組織を作ったあと、録音のタブを開くと落ちる

TalkLens では、録音のタブに警告のカードなどを足したあと、組織を作った状態で録音のタブを開くと、アプリが落ちるようになりました。落ちる時の表示は EXC_BAD_ACCESS で、呼び出しの記録(スタック)には、swift_getTypeByMangledName や SubstGenericParametersFromMetadata が、何重にも並んでいました。

SwiftUI の画面で EXC_BAD_ACCESS が起きる症状。実機では画面を開くと落ちるが、シミュレーターはスタックが大きいので同じ画面でも落ちない
実機でだけ落ちるので、原因を探しにくい

原因:ビューの型が深くなり、型の情報を作るだけでスタックを使い切る

SwiftUI は、画面を作る時に、ビューの型の情報を組み立てます。1つの body に、選択行、警告、送信待ちの表示などを入れ子で並べると、ビューの型がどんどん深くなります。

白い器が、重ねて積まれている写真
ビューの型が深くなり、スタックを使い切った(イメージ写真)
1つの body に選択行や警告や送信待ちを入れ子で並べるとビューの型が深くなり、型の情報を組み立てる再帰でメインスレッドのスタックを使い切って EXC_BAD_ACCESS で落ちる
画面の中身を計算する前に、型の組み立てで力尽きる

直し方:画面を、独立した struct の部品に分ける

直し方は、1つの body に詰め込まず、画面を独立した struct のビューに分けることでした。

色とりどりのブロックが、宙に舞っている写真
画面を、独立した部品に分けて直した(イメージ写真)
直し方。画面を独立した struct のビューに分ける、AnyView は避ける、メニューや繰り返しを含む行は具体的な struct にする、長い修飾子は ViewModifier にまとめる
型を浅くする4つの決まり

同じことが、不動産の業務アプリでも起きた

Kaitori Base でも、査定のタブが実機でだけ落ちました。

録音のアプリと不動産の業務アプリの2つで、実機でだけ落ちる原因が同じだった。最初の対策では足りず、本体と修飾を分けて根本から直した
見た目が違っても、原因は同じだった
  1. 最初は、Binding の書き方を変えて対策した

    階層の深い Binding の動的なメンバーをやめ、明示的な Binding にしました(ビルド35)。

  2. そのあと、根本から直した

    本体と修飾を独立した構造体に分け、折りたたみの中身は、開いた時にだけ作る形にしました。

見た目は違っても、原因は同じでした。1つの body に詰め込みすぎると起きる、ということが、2つのアプリで確かめられました。

再現のしかた:スタックを小さくして、UI テストで確かめる

実機でしか落ちないと、直したかどうかを確かめにくくなります。

スタックの大きさを1MBや512KBに絞った構成を作ると、シミュレーターでも落ちる。その構成で画面を開く UI テストを作り、直したあとも落ちないことを確かめる
実機に頼らずに、再現と確認ができる

まとめ

SwiftUI の画面を開くと落ちる:EXC_BAD_ACCESS の原因は、ビューの型が深すぎて「スタックを使い切る」ことだった:要点のまとめ。特定の画面を実機で開くと EXC_BAD_ACCESS で落ちる原因の1つは、ビューの型が深くなって、スタックを使い切ること
この記事の要点
  • 特定の画面を実機で開くと EXC_BAD_ACCESS で落ちる原因の1つは、ビューの型が深くなって、スタックを使い切ること
  • シミュレーターはスタックが大きいので、再現しにくい
  • 画面を独立した struct の部品に分け、AnyView は避け、修飾子は ViewModifier にまとめる
  • スタックを 1MB・512KB に絞った構成と UI テストで、再現と確認ができる
  • 録音のアプリと不動産の業務アプリで、同じ原因が起きた

この記事は、AI(Claude)の支援を受けて作成し、筆者が内容を確認しています。

  • SwiftUI
  • EXC_BAD_ACCESS
  • クラッシュ
  • スタックオーバーフロー
  • iOS
  • UIテスト

関連する記事

この記事に関連するサービス・アプリ

ブログの一覧へ