Identifiable プロトコルと id 指定
SwiftUI の List や ForEach でデータを表示する際、各要素を一意に識別するための仕組みが必要です。Identifiable プロトコルと id パラメータについて解説します。
なぜ識別子が必要なのか
SwiftUI はリストの各要素を追跡し、データが変更されたときに効率的に UI を更新します。この追跡には一意の識別子が必要です。識別子がないと、要素の追加・削除・並び替え時に正しくアニメーションできなかったり、パフォーマンスが低下したりします。
id パラメータによる識別
最もシンプルな方法は、ForEach や List に id パラメータを渡すことです。
struct ContentView: View {
let fruits = ["りんご", "みかん", "バナナ"]
var body: some View {
List(fruits, id: \.self) { fruit in
Text(fruit)
}
}
}id: \.self は要素そのものを識別子として使うことを意味します。String や Int など Hashable に準拠した型で使えますが、重複する値があると問題が発生します。
// 危険な例:重複する値がある
let items = ["A", "B", "A", "C"] // "A" が重複
List(items, id: \.self) { item in
Text(item)
}重複があると SwiftUI は同じ要素として扱ってしまい、意図しない動作の原因になります。
Identifiable プロトコル
カスタム型を使う場合は、Identifiable プロトコルに準拠させるのがベストプラクティスです。
struct Task: Identifiable {
let id = UUID()
var title: String
var isCompleted: Bool
}Identifiable に準拠するには、id プロパティを実装するだけです。UUID を使えば自動的に一意の値が生成されます。
struct TaskListView: View {
let tasks = [
Task(title: "買い物", isCompleted: false),
Task(title: "掃除", isCompleted: true),
Task(title: "洗濯", isCompleted: false)
]
var body: some View {
List(tasks) { task in
HStack {
Text(task.title)
Spacer()
if task.isCompleted {
Image(systemName: "checkmark")
}
}
}
}
}Identifiable に準拠した型を使う場合、id: パラメータは省略できます。
既存のプロパティを id として使う
データベースから取得したデータなど、すでに一意の ID を持っている場合は、それを使うこともできます。
struct User: Identifiable {
let id: Int // データベースの主キー
var name: String
var email: String
}新規に作成するデータで、永続化の必要がない場合に便利。自動的に一意な値が生成される。
データベースや API から取得したデータで、すでに一意の ID が割り当てられている場合に使用。
id にキーパスを指定
Identifiable に準拠していない型でも、id パラメータにキーパスを指定すれば使えます。
struct Item {
let code: String
var name: String
}
struct ContentView: View {
let items = [
Item(code: "001", name: "商品A"),
Item(code: "002", name: "商品B"),
Item(code: "003", name: "商品C")
]
var body: some View {
List(items, id: \.code) { item in
Text(item.name)
}
}
}id: \.code で code プロパティを識別子として使用しています。ただし、可能であれば Identifiable プロトコルに準拠させる方が Swift らしい書き方です。













