SwiftUIにおける「Identifiable」について…

朝の実(Asanomi)アイコン アプリ開発

SwiftUI でアプリを作ると、必ずと言っていいほど登場する Identifiable。今回は、なぜモデルに Identifiable を付けるのか、SwiftUI が内部で何をしているのか、実務経験が浅くても理解できるよう丁寧に解説します。

Identifiable とは?

Identifiable は「そのデータが何者かを一意に示す ID を持っていること」を表すプロトコルです。

SwiftUI の ListForEach は、データを並べて表示するときに、「どのデータがどのセルなのか?」を判断する必要があります。
そのときに使われるのが id です。

Identifiable に準拠するには、実は必要な条件はたった 1つだけです。

  • 一意の id を持っていること

例えば SNS の投稿 Post モデルでは、次のように id を持たせます。

struct Post: Identifiable {
    let id: String   // ← これだけで Identifiable になる
    let text: String
}

この id を SwiftUI が使って、表示の更新時に「同じ投稿かどうか」を判断します。
以下のように、PostIdentifiable に準拠している場合、List はとてもシンプルに書けます。

// Post が Identifiable 準拠の場合
struct Post: Identifiable {
    let id: String
    let text: String
}

List(posts) { post in
    Text(post.text)
}

一方、Post が Identifiable に準拠していない場合は、List に「どのプロパティを ID として使うか」を毎回教えてあげる必要があります。

// Identifiable に準拠していない場合
struct Post {
    let id: String
    let text: String
}

// List 側で「id を識別子にして」と明示する必要がある
List(posts, id: \.id) { post in
    Text(post.text)
}

どちらも動きますが、モデル側を Identifiable にしておくと。

  • List / ForEach の呼び出しが毎回スッキリする
  • 「この型は必ず一意なIDを持っている」という前提がコード上で明示できる
  • タイムラインなど別の画面でも、そのまま再利用しやすい

そのため、投稿やユーザーなど「ID を持つことが前提のモデル」は、最初から Identifiable に準拠させておくのがおすすめです。

Identifiable に準拠していないデータの場合、List に渡すときに id: を指定しなければいけませんが、Identifiable を実装していれば余計な指定は不要です。

つまり Identifiable は、SwiftUI の List / ForEach を「自然に使える状態」にするための “身分証明書” のようなものです。


なぜSwiftUIでIdentifiableが重要なのか?

SwiftUI の ListForEach は、「どのデータがどの行に対応しているか」を常に追跡しています。データの更新時には、id を元に差分を計算し、必要な部分だけを再描画します。

例えば:

List(posts) { post in
    Text(post.text)
}

このとき SwiftUI は、posts 配列内の各 post が “どのセルか” を識別するために post.id を使用します。

もし id がなければどうなるか?

  • 行のどれが削除されたのか判断できない
  • どれが更新されたのか判別できない
  • すべてのセルが作り直されてスクロール位置が飛ぶ
  • アニメーションが不自然になる

つまり、Identifiable はSwiftUIの差分更新の基盤です。


Identifiable を使う具体例

私の開発しているアプリ「朝の実」で使っている Post モデルは以下のようになっています。

struct Post: Identifiable {
    let id: String    // ここがID
    let authorId: String
    let text: String
    let createdAt: Date
    var cheerCount: Int
    var isDeleted: Bool
    let clientTimeZone: String
}

ID に何を使うべき?

SwiftUI やデータモデル設計では、「そのデータを一意に識別できる ID」をどう設計するかがとても重要です。以下に、一般的に推奨される ID の選び方をまとめます。

① 永続的に変わらない ID を使う(UUID / データベースIDなど)

アプリを再起動しても変わらない ID を使うのが最も安全です。
例えば、投稿・ユーザー・コメントなどは、毎回同じ ID を参照できる必要があります。

よく使われるのは:

  • UUID(UUID().uuidString
  • バックエンド側のユニーク ID(データベースが生成したもの)

これらは「一意性が保証された値」であり、競合や重複が起こらないため、ID に最適です。

また、Swift では UUID を以下のように生成します。

let id = UUID().uuidString

UUID は衝突する可能性が極めて低く、ほぼ確実に一意な ID として利用できます。

② index(配列の順番)を ID にしてはいけない

配列の添字(0, 1, 2…)を ID として使うのは絶対に避けるべきです。

  • 並び順が変わった瞬間に ID が変わる
  • データを削除すると、後ろの全要素の ID が変わる
  • SwiftUI の差分計算が正しく動かなくなる

「不安定な ID」は SwiftUI の描画バグや、リスト更新時のクラッシュにつながります。

要するに ID は “変わらない一意な値” を使う

アプリのモデルが扱う ID は、次の条件を満たしていることが重要です:

  • 一意である(他と重複しない)
  • 永続的である(並び順や操作で変化しない)

Post、User、Comment など「実体を識別するデータ」は、UUID を ID にしておくのが最も安全で実務でも一般的です。


まとめ

  • Identifiable = 個体識別のためのプロトコル
  • id を使って SwiftUI が差分更新(Diffing)する
  • List / ForEach / アニメーションで必須の存在

SwiftUI を使ううえで Identifiable の理解は避けて通れません。 今回の記事が、モデル設計や UI 更新の仕組みを理解する一助になれば幸いです。

sho shimizu

SwiftUI を用いたiOS アプリの個人開発を行っています。
これまでに2本のアプリを App Store にリリースしました。

現在は、朝専用SNS「朝の実(Asanomi)」を開発中です。
CloudKitやSwift Concurrencyを用いた実装を進めながら、
設計や実装上で整理した内容を技術記事にまとめています。

sho shimizuをフォローする
アプリ開発技術解説朝の実
シェアする
sho shimizuをフォローする