「iCloud が新しければ取り込む」の関数が、何も比べていなかった:応募の記録が 20 件から 1 件になりうる

English version

トレカダッシュ 開発の記録 / 2026年8月

iOS アプリ「トレカダッシュ」には、利用者が自分で書きためる応募の記録があります。どの抽選に応募したか、結果はどうだったか。手で積み上げた個人の記録なので、失うと取り返せません。

2026 年 8 月 23 日、まだ精読していなかったファイル(1,076 行)を読んで、この記録が、丸ごと消えうる経路を見つけました。きっかけは、関数の名前を信じていたことでした。

この記事は、2026 年 8 月 23 日の作業の記録から書いています。

名前は「新しければ取り込む」、中身は「何も比べない」

iCloud(Apple のクラウド)と同期する関数の名前は、loadFromICloudIfNewer、つまり「iCloud が新しければ、読み込む」です。ところが、中身は、新しいかどうかを一切見ておらず、iCloud に変更があると、その内容で、丸ごと置き換えていました。

これで、何が起きうるでしょうか。

  1. 端末 A に、応募の記録が 20 件ある(iCloud にも 20 件)。
  2. 端末 B を、新しくインストールする。iCloud の最初の同期は、非同期なので、起動した直後は、記録が空のことがある。
  3. 端末 B で、1 件、記録を追加する。保存の処理が、[1 件] を iCloud へ上書きする。
  4. 端末 A が、変更の通知を受けて、20 件から 1 件に置き換わる(19 件が消える)。

コードの中に、記録を書き出す、読み込む機能があったのは、「機種変更で、データが全部消えるのを防ぐため」と書かれていました。作った人も、この領域が壊れやすいことは、知っていたのです。

直し方:更新時刻を比べる、そして、空では上書きしない

分かったこと

関数の名前が仕様を語っていても、中身がそうとは限らない。

この話に出てくるもの

ほかの記録

コメント

感想や、記事の間違いの指摘は、ここへ。書くには、GitHub のアカウントが要ります。

押すと、giscus(giscus.app)と GitHub に接続します。押さなければ、接続しません。詳しくはあつかいに書いています。