「Identifiable」について…

朝の実アイコン Swift

SwiftUI を使ってアプリを開発していると、ほぼ必ず登場する Identifiable。しかし「なぜ必要なの?」「どんなとき使うの?」が最初は分かりにくいポイントです。

例えば SNS の投稿一覧画面を想像してください。画面には複数の投稿が表示され、どれか一つが更新されても、画面全体を作り直す必要はありません。
SwiftUI では、この「どの投稿がどの行か」を見分けるために ID を使います。


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 は何を使うべき?

ここからは、「ID の選び方」を初心者でも分かるように解説します。

① ID は「変わらない値」でなければならない

例えば配列の index(0,1,2…)を ID にすると:

  • 並べ替えで ID が変わる
  • 1つ削除すると後ろが全部ずれる
  • SwiftUI の差分計算が崩壊する

→ index を ID にするのは絶対に NG です。

② 一意性が保証されたものを使う(UUID が最適)

もっとも一般的で安全なのが UUID().uuidString です。重複する確率がほぼゼロなので、投稿やユーザー、コメントなどの ID に最適です。

let id = UUID().uuidString

③ バックエンドがある場合はそのIDを使う

CloudKit や Firebase などバックエンドが ID を生成する場合は、それをそのまま使えば OK。


まとめ

Identifiable は「個体を識別するためのIDを必ず持っている」ということを示す、SwiftUI にとって非常に重要なプロトコルです。特に ListForEach では、差分更新(Diffing)を行うために欠かすことができません。

本記事で取り上げた内容を整理すると、ポイントは次のとおりです。

  • Identifiable = データが一意の ID を持つことを保証するプロトコル
  • SwiftUI は id を使って「どのデータがどの行か」を正確に追跡する
  • List / ForEach の構文がシンプルになり、余計な指定が不要になる
  • 削除・更新・並べ替え時の UI 崩れを防ぎ、アニメーションも自然に保てる
  • モデル設計の初期段階で Identifiable を採用しておくと再利用性が高まる

特に SwiftUI の UI 更新は「差分ベース」で動いているため、安定した UI を作るには id が極めて重要です。投稿・ユーザー・コメントのように「実体を識別する必要があるデータ」は必ず Identifiable にしておくとよいでしょう。

今回の解説が、SwiftUI のデータ構造理解やモデル設計の指針として役立てば幸いです。