【SwiftUI】Realmでプライマリーキーの設定方法!UUIDを指定
この記事からわかること
- Realm Swiftでプライマリーキーを扱う方法
- Swift UIでの実装方法
- UUIDを使った重複しないキー指定
- ObjectIdを使った重複しないキー指定
- エラー:Attempting to create an object of type 'クラス名' with an existing primary key value '値'.
- エラー:\'クラス名\' does not have a primary key and can not be updated"
- エラー:Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=10 "Migration is required due to the following errors:
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
モバイル向けのデータベースを提供しているRealm Swiftの扱いの中でプライマリーキーを設定する方法をまとめていきます。
Realm Swiftでプライマリーキーを設定する方法
Realm Swiftはデータベースなのでプライマリーキーを指定することも可能です。プライマリーキーとは指定したカラムに重複した値が入らないようにするための設定です。
設定するにはテーブルクラスを定義する際にprimaryKey
メソッドをオーバーライドしてプライマリーキーに指定したいプロパティ名をリターンします。
class User: Object {
@Persisted var id:String = ""
@Persisted var name:String = ""
@Persisted var age:Int = 0
override static func primaryKey() -> String? {
return "id"
}
}
これでid
にはプライマリーキーが重複した値を持つオブジェクトの格納が許可されなくなりました。
@Persistedのイニシャライザから設定する
プロパティラッパーの@Persisted
のイニシャライザを使用することでもプライマリーキーを設定することが可能です。
class User: Object {
@Persisted(primaryKey: true) var id:String = ""
@Persisted var name:String = ""
@Persisted var age:Int = 0
}
Attempting to create an object of type 'クラス名' with an existing primary key value '値'.
しかしこの状態であえて重複した値を持つオブジェクトを入れ込もうとすると以下のようなエラーが発生し、アプリが停止してしまいます。
"Attempting to create an object of type 'User' with an existing primary key value '1'."
// 「既存の主キー値 '1' でタイプ 'User' のオブジェクトを作成しようとしています。」
これを解決する方法はaddメソッドの定義に載っていました。
引用:addメソッドの定義
”オブジェクト型に主キーがないか、指定された主キーを持つオブジェクトがない場合 既に存在する場合、レルムに新しいオブジェクトが作成されます。レルムにオブジェクトがすでに存在する場合 指定された主キーと更新ポリシーが `.modified` または `.all` の場合、既存の オブジェクトが更新され、そのオブジェクトへの参照が返されます。”
なのでアプリが落ちてしまうのを防ぐためにadd
メソッドの引数にupdate:.modified
を指定します。これで重複したオブジェクトを新規で追加することなく、一致したキーのデータを新しいオブジェクトで更新してくれます。
Button(action: {
let user = User()
user.id = "1"
user.name = "ame"
user.age = 72
let relam = try! Realm()
try! relam.write{
relam.add(user,update:.modified)
}
}, label: {
Text("User追加")
})
これで上記のボタンを何度押してもアプリが落ちることはなくなります。
\'クラス名\' does not have a primary key and can not be updated"
逆にプライマリーキーを指定せずにupdate:.modified
を指定してしまうと以下のようなエラーが発生してしまうので注意してください。
\'User\' does not have a primary key and can not be updated"
UUIDを使った一意のID
上記では一意の値のみを許可したid
プロパティをString
型で定義していましたが、Realm SwiftではUUIDも使用可能です。
おすすめ記事:【Swift UI】UUIDとは?使用方法
SwiftではUUIDが128bit(=16byte)の数値として表されデータ型はUUID型になります。指定する際はUUID
構造体をインスタンス化して初期値に指定すればOKです。
class User: Object {
@Persisted var id = UUID()
@Persisted var name:String = ""
@Persisted var age:Int = 0
override static func primaryKey() -> String? {
return "id"
}
}
これで追加するたびに一意のid値が生成されるので、重複を気にすることなく使用可能になります。
Results<User> <0x12d605990> (
[0] User {
id = 6941288C-6411-438A-B231-850CDE066287;
name = ame;
age = 230;
},
[1] User {
id = 4E3E0674-6F04-4BC8-8AB6-1C69E5A7F417;
name = ame;
age = 230;
}
)
ObjectIdを使った一意のid
UUIDと同様に初期値として一意の値を付与できる方法にRealm Swiftライブラリで使用できるObjectId
があります。これは12バイトの一意の英数字の羅列が生成されます。またこの識別子でソートをかけると生成された順番に整列されるように割り振られます。
class User: Object {
@Persisted(primaryKey: true) var id: ObjectId
@Persisted var name:String = ""
@Persisted var age:Int = 0
}
これで追加するたびに一意のid値が生成されるので、重複を気にすることなく使用可能になります。
Results<User> <0x12d605990> (
[0] User {
id = 6332fc79008dcaf2c0135526;
name = ame;
age = 230;
},
[1] User {
id = 6332ff27131e9c4275156b67;
name = ame;
age = 230;
}
)
途中でプライマリーキーを追加するとエラーになる
class User: Object {
@Persisted var id:String = ""
@Persisted var name:String = ""
@Persisted var age:Int = 0
// 最初は指定せずに後から以下を追加した場合
// override static func primaryKey() -> String? {
// return "id"
// }
}
プライマリーキーを最初指定しないまま使用していた場合に後からプライマリーキーを指定してしまうと以下のようなエラーになってしまいます。
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=10 "Migration is required due to the following errors:
これは定義済みのRealmクラス(テーブル定義)と保存されているRealmオブジェクト(テーブル内のレコード)の定義が不一致を起こすためです。
この場合は一度アプリ自体をデバイスから削除するかマイグレーションを使用することで解決できます。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。
私がSwift UI学習に使用した参考書
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。