【Swift UI】Identifiableとは?プロトコルとUUIDの使い方

この記事からわかること
- SwiftのIdentifiableとは?
- Initializer 'init(_:rowContent:)' requires that 'String' conform to 'Identifiable'のエラー原因
- Identifiableプロトコルとは?
index
[open]
\ アプリをリリースしました /
配列を元にList{}
を使ってリストを作成する時にエラーが発生し、「Identifiable」という言葉が出てきたのでその意味と原因をまとめていきたいと思います。
List作成時に起きるエラーの原因
Swift UIのList{}
を使って配列をリスト表示させようとした場合に以下のようなエラーが発生しました。
エラー
Initializer 'init(_:rowContent:)' requires that 'String' conform to 'Identifiable'
// イニシャライザー'init(_:rowContent :)'では、'String'が'Identizable'に準拠している必要があります
原因のコード
struct ContentView: View {
let langs = ["HTML", "PHP", "Swift"]
var body: some View {
List(langs){ lang in
Text(lang)
}
}
}
List{}
はクロージャ内に記述したコンテンツをリスト形式で描画してくれます。記述方法はコンテンツは1つずつ列挙して記述する方法と配列などのまとまったデータの中から1つずつループして取り出す方法などがあります。
そもそもList(配列)
と言う記述形式を取りたい場合はIdentifiableプロトコル
に準じた構造でないと取り出せないようです。
そのため上記(後者として記述したつもり)の方法では配列の要素を一意に識別できるキー値がないため、配列の値を取り出すことができないようです。
なので配列に識別子となるid
を振ることで解決することができます。
Identifiableプロトコルとは?
Identifiableプロトコルとはidプロパティを必須とするプロトコルです。
プロトコルとはクラスや構造体などを定義する際の規約や規格を定義しているルールのようなものです。Swiftでは予め色々な種類のプロトコルが定義されており、その中に「Identifiableプロトコル
」が存在します。ちなみにIdentifiableとは「識別可能」という意味の英単語です 。
Identifiableプロトコルの定義
public protocol Identifiable {
/// A type representing the stable identity of the entity associated with `self`.
associatedtype ID : Hashable
/// The stable identity of the entity associated with `self`.
var id: Self.ID { get }
}
定義元を見ると必須のプロパティとしてid
が定義されています。
ポイント
- Identifiableプロトコルはidを持つことをルールとした規格
配列をプロトコルに準ずるために
配列の中に定義する要素を構造体として保持することでプロトコルに準じたデータにしていきます。まずは構造体を定義します。
struct Lang: Identifiable {
var id: String
var name: String
}
配列の各要素を構造体Lang
に準拠する形で定義します。
struct ContentView: View {
let langs = [
Lang(id: "1" ,name: "HTML"),
Lang(id: "2" ,name: "PHP"),
Lang(id: "3" ,name: "Swift")
]
var body: some View {
List(langs){ lang in
Text(lang.name)
}
}
}
この方法だとidを手打ちで定義しないといけません。これを解決してくれるのがUUIDです。
UUIDとは?
UUID(Universally Unique IDentifier)とはSwift独自のものではなく、識別子の標準規格です。Swiftでは128bit(=16byte)の数値として表されデータ型はUUID型になります。文字列として取得(表示)したい場合はUUID型オブジェクトの uuidStringプロパティ
を使うとString型
の値として取得できます。その際は16進数表記になります。
使用するにはFoundationフレームワーク
の読み込みが必要になります。
import Foundation
struct Lang: Identifiable {
var id = UUID()
var name: String
}
let langs = [
Lang(name: "HTML"),
Lang(name: "PHP"),
Lang(name: "Swift")
]
print(langs[0].id) // 8ABE0F22-0EEF-478E-A709-3F271B932AFE
dump(type(of: langs[0].id)) // Foundation.UUID.Type
dump(type(of: langs[0].id.uuidString)) // String.Type
一意でなければいけないidプロパティは初期値にUUID()構造体を使うと自動で一意となるidを割り振ってくれます。
import Foundation
struct Lang: Identifiable {
var id = UUID()
var name: String
}
あとは配列の中のデータ構造体に則った形で整形し配列としてまとめてListに渡せば完了です。UUID構造体を初期値にしている場合、明示的なidプロパティへの値の格納は不要になります。
struct ContentView: View {
let langs = [
Lang(name: "HTML"),
Lang(name: "PHP"),
Lang(name: "Swift")
]
var body: some View {
List(langs){ lang in
Text(lang.name)
}
}
}
構造体を使わずに配列を取り出す
配列にわざわざidを振らなくともListの記述形式を変更すれば取り出すことも可能です。
struct ContentView: View {
let langs = ["HTML", "PHP", "Swift"]
var body: some View {
List(langs.indices, id:\.self){ index in
Text(langs[index])
}
}
}
配列.indices
で「0..<配列の要素数」のレンジを取得できます。indexに格納されるのは0〜配列の要素数
までの数なので配列[index]
としてindex番目の要素を取り出す点に注意してください。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。