【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では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学習に使用した参考書

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index