MENU

【Swift入門】Identifiableとは?使い方を初心者向けに徹底解説

SwiftUIでアプリを開発していると、Identifiableというプロトコルに出会うことがあります。特にリストやForEachを使うときに頻繁に登場しますが、「なぜ必要なのか?」「どう使えばいいのか?」と疑問に思う方も多いでしょう。

この記事では、Swift初心者の方でも理解できるように、Identifiableプロトコルの基本から実践的な使い方まで、わかりやすく解説します。

目次

Identifiableとは?

Identifiableは、オブジェクトを一意に識別するためのSwiftのプロトコルです。

簡単に言えば、「このオブジェクトには他と区別できる固有のIDがありますよ」ということをSwiftに伝えるための仕組みです。

なぜIdentifiableが必要なのか?

SwiftUIでリストを表示する際、システムは各要素を区別する必要があります。例えば:

  • リストの中で特定の項目が更新された
  • 新しい項目が追加された
  • 項目が削除された

これらの変更を正確に追跡するために、各オブジェクトに固有のIDが必要になります。Identifiableは、この問題をエレガントに解決してくれます。

Identifiableの基本構造

Identifiableプロトコルの定義は非常にシンプルです。

protocol Identifiable {
    associatedtype ID: Hashable
    var id: ID { get }
}

必要なのは、idというプロパティを持つことだけです。このIDはHashableである必要があります(一意性を保証するため)。

Identifiableの基本的な使い方

ステップ1: 構造体を定義してIdentifiableに準拠させる

最もシンプルな実装例を見てみましょう。

import Foundation

struct User: Identifiable {
    let id = UUID()
    var name: String
    var email: String
}

これだけで、User構造体はIdentifiableプロトコルに準拠します。

ポイント:

  • UUID()は自動的に一意の識別子を生成してくれる
  • letで宣言することで、IDが変更されないことを保証

ステップ2: SwiftUIのリストで使う

Identifiableに準拠したオブジェクトは、SwiftUIのリストで簡単に使えます。

import SwiftUI

struct ContentView: View {
    let users = [
        User(name: "山田太郎", email: "taro@example.com"),
        User(name: "佐藤花子", email: "hanako@example.com"),
        User(name: "鈴木次郎", email: "jiro@example.com")
    ]
    
    var body: some View {
        List(users) { user in
            VStack(alignment: .leading) {
                Text(user.name)
                    .font(.headline)
                Text(user.email)
                    .font(.subheadline)
                    .foregroundColor(.gray)
            }
        }
    }
}

Identifiableを使う場合と使わない場合の比較

Identifiableの便利さを理解するために、使わない場合と比較してみましょう。

Identifiableを使わない場合

struct Book {
    var title: String
    var author: String
}

struct BookListView: View {
    let books = [
        Book(title: "Swift入門", author: "山田太郎"),
        Book(title: "SwiftUI実践", author: "佐藤花子")
    ]
    
    var body: some View {
        List(books, id: \.title) { book in
            Text(book.title)
        }
    }
}

id: \.titleのように、毎回どのプロパティをIDとして使うか指定する必要があります。

Identifiableを使う場合

struct Book: Identifiable {
    let id = UUID()
    var title: String
    var author: String
}

struct BookListView: View {
    let books = [
        Book(title: "Swift入門", author: "山田太郎"),
        Book(title: "SwiftUI実践", author: "佐藤花子")
    ]
    
    var body: some View {
        List(books) { book in
            Text(book.title)
        }
    }
}

idの指定が不要になり、コードがシンプルで読みやすくなります。

実践的なサンプル:ToDoアプリ

より実践的な例として、ToDoアプリのデータモデルを作ってみましょう。

import Foundation
import SwiftUI

struct TodoItem: Identifiable {
    let id = UUID()
    var title: String
    var isCompleted: Bool
    var priority: Priority
    var createdAt: Date
    
    enum Priority: String, CaseIterable {
        case low = "低"
        case medium = "中"
        case high = "高"
    }
}

struct TodoListView: View {
    @State private var todos = [
        TodoItem(title: "買い物に行く", isCompleted: false, priority: .medium, createdAt: Date()),
        TodoItem(title: "メールを返信する", isCompleted: true, priority: .high, createdAt: Date()),
        TodoItem(title: "資料を作成する", isCompleted: false, priority: .low, createdAt: Date())
    ]
    
    var body: some View {
        NavigationView {
            List(todos) { todo in
                HStack {
                    Image(systemName: todo.isCompleted ? "checkmark.circle.fill" : "circle")
                        .foregroundColor(todo.isCompleted ? .green : .gray)
                    
                    VStack(alignment: .leading) {
                        Text(todo.title)
                            .strikethrough(todo.isCompleted)
                        Text("優先度: \(todo.priority.rawValue)")
                            .font(.caption)
                            .foregroundColor(.secondary)
                    }
                }
            }
            .navigationTitle("やることリスト")
        }
    }
}

このサンプルでは、TodoItemIdentifiableに準拠しているため、複雑な構造体でもリストで簡単に扱えます。

IDの種類と選び方

IdentifiableのIDには、いくつかの選択肢があります。

1. UUID(最も推奨)

struct Item: Identifiable {
    let id = UUID()
    var name: String
}

メリット:

  • 自動的に一意のIDを生成
  • 衝突の心配がほぼゼロ
  • 追加のロジックが不要

使用場面: ほとんどの場合でこれを使えばOK

2. カスタムID(文字列や数値)

struct Product: Identifiable {
    let id: String  // 商品コード
    var name: String
    var price: Int
}

let products = [
    Product(id: "PRD001", name: "ノートPC", price: 150000),
    Product(id: "PRD002", name: "マウス", price: 3000)
]

メリット:

  • APIから取得したデータをそのまま使える
  • 人間が読みやすいIDを使える

使用場面: サーバーから取得したデータを扱う場合

3. Int型のID

struct Student: Identifiable {
    let id: Int  // 学籍番号
    var name: String
    var grade: Int
}

注意点: IDの重複に注意が必要

よくあるエラーと対処法

エラー1: “Type ‘XXX’ does not conform to protocol ‘Identifiable'”

原因: idプロパティが定義されていない、または型がHashableでない

解決方法:

// ❌ 間違い
struct Item: Identifiable {
    var name: String
}

// ✅ 正しい
struct Item: Identifiable {
    let id = UUID()
    var name: String
}

エラー2: リストの更新がうまくいかない

原因: IDが変更可能(var)になっている、またはIDが重複している

解決方法:

// ❌ 間違い
struct Item: Identifiable {
    var id = UUID()  // varはダメ
    var name: String
}

// ✅ 正しい
struct Item: Identifiable {
    let id = UUID()  // letを使う
    var name: String
}

エラー3: ForEachで”id: .self”が必要と言われる

原因: オブジェクトがIdentifiableに準拠していない

解決方法: 構造体にIdentifiableを追加するか、id: \.selfを指定する

// 方法1: Identifiableに準拠させる(推奨)
struct Item: Identifiable {
    let id = UUID()
    var name: String
}

List(items) { item in
    Text(item.name)
}

// 方法2: id: \.selfを使う
struct Item {
    var name: String
}

List(items, id: \.self) { item in
    Text(item.name)
}

Identifiableを使う際のベストプラクティス

1. IDは常にletで宣言する

struct User: Identifiable {
    let id = UUID()  // ✅ let
    var name: String
}

IDが変更されると、SwiftUIが正しく追跡できなくなります。

2. UUIDを使うのが最も安全

特別な理由がない限り、UUID()を使うのが最も確実です。

3. カスタムIDを使う場合は一意性を保証する

struct Product: Identifiable {
    let id: String
    var name: String
    
    init(id: String, name: String) {
        assert(!id.isEmpty, "IDは空にできません")
        self.id = id
        self.name = name
    }
}

4. Codableと併用する場合

APIからデータを取得する際は、両方のプロトコルに準拠させます。

struct User: Identifiable, Codable {
    let id: UUID
    var name: String
    var email: String
}

Identifiableが活躍する場面

リスト表示

List(items) { item in
    Text(item.name)
}

ForEachループ

ForEach(users) { user in
    UserRow(user: user)
}

NavigationLink

ForEach(articles) { article in
    NavigationLink(destination: ArticleDetailView(article: article)) {
        Text(article.title)
    }
}

アニメーション付きの要素追加・削除

Identifiableがあることで、SwiftUIは要素の追加や削除を正確に追跡し、スムーズなアニメーションを実現できます。

まとめ

この記事では、SwiftのIdentifiableプロトコルについて解説しました。

重要なポイント:

  • Identifiableはオブジェクトを一意に識別するためのプロトコル
  • idプロパティを持つだけで準拠できる
  • SwiftUIのリストやForEachで使うとコードがシンプルになる
  • IDはletで宣言し、基本的にはUUID()を使う
  • APIからのデータには既存のIDを使ってもOK

Identifiableを正しく使うことで、SwiftUIアプリの開発がより効率的になり、バグも減らせます。リストを扱うアプリを作る際は、ぜひ積極的に活用してみてください。

プログラミングの独学におすすめ
プログラミング言語の人気オンラインコース
独学でプログラミングを学習している方で、エラーなどが発生して効率よく勉強ができないと悩む方は多いはず。Udemyは、プロの講師が動画で実際のプログラムを動かしながら教えてくれるオンライン講座です。講座の価格は、セール期間中には専門書籍を1冊買うよりも安く済むことが多いです。新しく学びたいプログラミング言語がある方は、ぜひUdemyでオンライン講座を探してみてください。
目次