# iOS アプリが固まって強制終了される（0x8BADF00D）：SwiftUI の計算プロパティが毎回走っていた

> 実機のログにあった 0x8BADF00D（watchdog）。951件の記事を、画面を描き直すたびにメインスレッドで数え直していた。原因の特定と、バックグラウンドで計算する形に直した記録。

- URL: https://koshinstudio.com/notes/torecadash-watchdog/
- 公開: 2026-10-08
- 書いた人: Koshin（https://koshinstudio.com/about/）
- サイト: Koshin Studio

  English version (https://koshinstudio.com/en/notes/torecadash-watchdog/)

トレカダッシュ 開発の記録 ／ 2026年10月

  iOS アプリ「トレカダッシュ」で、「なんかアプリ、めっちゃクラッシュする」という報告がありました。実機のログを読むと、アプリが固まって、OS に強制終了されていたことが分かりました。原因は、画面を描き直すたびに、951件の記事を毎回数え直していたことでした。コミットの記録で書きます。

  このサイトには、トレカダッシュの作品ページはまだありません。ここに書くのは、開発の記録です。

## ログに残っていたもの

  実機のハングのログには、0x8BADF00D という終了コードと、Failed to terminate gracefully after 5.0s という一行がありました。5秒以内に応答しないアプリを、OS（watchdog）が強制終了したという意味です。メインスレッドは、NSKeyedArchiver を経由する処理で止まっていました。また、端末は発熱していて（Thermal State: serious）、普段なら一瞬で終わる処理が、5秒を超えていました。

## 本当の原因

  固まっていたのは、「フォロー中」タブの、商品の記事一覧です。記事が951件あるケースでした。

  記事の一覧（articles）が、ただの計算プロパティになっていました。SwiftUI は、画面（body）を何度も評価し直します。記事のデータが変わっていないときも、です。そのたびに、951件に対して、絞り込み4回・変換・並べ替えを、メインスレッドで毎回やり直していました。

  普段は一瞬で終わるので、気づきません。発熱で端末が遅くなったときだけ、5秒を超えて、強制終了になります。

## 直し方

  記事のデータ、受け取り方法、並べ替えの3つが、実際に変わったときだけ、バックグラウンドのスレッドで計算し直すことにしました。結果は、表示用の状態（displayArticles、@State）に入れます。これで、メインスレッドを塞がなくなります。

  // （イメージです。実際のコードそのものではありません）
// 前：body を評価するたびに、毎回
var articles: [Article] { fetched.filter…filter…map…sorted }

// 後：変わったときだけ、裏で計算して、結果を持っておく
@State var displayArticles: [Article] = []
// fetchedArticles / receiveMode / sortOption が変わったときに再計算

## 確かめられていないこと

  コミットに書かれている確認は、xcodebuild でビルドが成功した（BUILD SUCCEEDED）ことだけです。実機で、固まらなくなったことは、記録にありません。発熱している状態は、再現しにくいので、確かめるのも簡単ではありません。この記事では、「直した」ではなく、「原因を特定して、直す方式に変えた」と書いておきます。

## 分かったこと

> 普段は一瞬で終わる処理は、遅い日にだけ、アプリを止める。
  計算プロパティは、書くのが楽です。ただ、画面が描き直されるたびに実行される場所に置くと、データの量に比例して、遅くなります。951件は、少なくない数です。「何回呼ばれるか」を意識して置き場所を決める、という当たり前のことを、実機のログで教わりました。

  この記事は、コミット（2026年10月5日）の記録から書きました。

  この話に出てくるもの

- 「減るはず」が、二度外れた (https://koshinstudio.com/notes/torecadash-ai/) — 同じアプリの、AI への問い合わせの記録

- TestFlight にビルドが来ない原因を、一度間違えた (https://koshinstudio.com/notes/torecadash-ci/) — 同じアプリの、別の記録
