概要
iOSアプリ開発経験はあるのですが、
SwiftUIはあまりやったことがなく修行中・・・!
その際「Identifiable」というプロトコルに出くわした際
理解が難しかったので記事にしました。
開発環境
・macOS Sonoma
・Xcode16
・iOS 18
きっかけ
下記のコードを記載した際にとあるエラーが出てきました。
// エラーが出たコード
import SwiftUI
struct User {
let id: Int
let name: String
let age: Int
}
struct ContentView: View {
var users: [User] = []
var body: some View {
VStack {
ForEach(users) { user in // <- ここでコンパイルエラーになる
Text("\(user.name)")
}
}
}
}
そしてコンパイルエラー内容は
Referencing initializer ‘init(_:content:)’ on ‘ForEach’ requires that ‘Book’ conform to ‘Identifiable’
Identifiableが必要な理由
どうやらListやforEachの性質にヒントがあったみたいです。
(ヒントになった記事↓)
実はforEachのような繰り返し処理の場合、SwiftUIはデータの中身を見ないそうです!!
じゃあどうする?
ではSwiftUIはどのように判別するのでしょうか?
それはデータの中身を見に行くのではなく、
IDなどで識別可能にしておき、
それぞれの要素にアクセスすることが可能となります。
そこで、Identifiableの出番です!
改善後のソースコード
Identifiableプロトコルに準拠させることで解決します。
// IdentifiableでUser構造体のデータを判別させる
struct User:Identifiable {
let id = UUID() // 独自のidを実装
let name: String
let age: Int
}
struct ContentView: View {
var users: [User] = []
var body: some View {
VStack {
ForEach(users) { user in // コンパイルエラーが消える
Text("\(user.name)")
}
}
}
}
Identifiableプロトコルについてもう少し
public protocol Identifiable<ID> {
/// ①
/// A type representing the stable identity of the entity associated with
/// an instance.
associatedtype ID : Hashable
/// ②
/// The stable identity of the entity associated with this instance.
var id: Self.ID { get }
}
①ではIDという名前の関連型を定義しており、
このID型がHashableに準拠している必要があることを意味しています。
Hashable:
一意性の比較やコレクション(例:SetやDictionary)に使用するため、
IDがハッシュ可能である必要があります。
ハッシュ可能なると、高速なデータ検索や同一性の確認ができます。
②では各インスタンスが一意の識別子を持っていることを保証しています。
やることはシンプルですが、仕組みが少々複雑でしたので
一旦まとめてみました。