質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

615閲覧

【RealmSwift】画面を更新するたびにプライマリーキーとなるIDに1加えるようにしたいです

miyuki

総合スコア23

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2022/08/24 15:15

実現したいこと・前提

ユーザーが画面を離れたらその時点で書かれているデータを保存し、再度その画面(CleanViewController)に戻ってきたらまた新しくデータを打ち込めるようなアプリを作っています。

プライマリーキーをIDにしていて、画面を離れる瞬間(viewWillDisappear)で現時点で最大のIDを取得し、その値に1を足しています。

発生している問題・エラーメッセージ

CleanViewController内のTextViewに文字を打ち込む→画面を離れデータを保存させる→再度CleanViewControllerのTextViewにテキストを入れる→画面を離れる
このような処理をした際下記のようなエラーが出てしまいます。
1回目のデータを保存させる処理は上手くいっているのですが、再度CleanViewControllerに戻り保存させようとするとうまくいかないです。

Primary key can't be changed after an object is inserted

該当のソースコード

Swift

1class CleanViewController: UIViewController { 2 @IBOutlet weak var textField: UITextField! 3 let realm = try! Realm() 4 let clean = Clean() 5 var postResults = try! Realm().objects(Post.self).sorted(byKeyPath: "date", ascending: false) 6 7 override func viewWillAppear(_ animated: Bool) { 8 textField.text = "" 9 } 10 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 } 14 15 override func viewWillDisappear(_ animated: Bool) { 16 let date = Date() 17 if textField.text!.isEmpty == false { 18 let allPosts = realm.objects(Clean.self) 19 if allPosts.count != 0{ 20 print(clean.id) 21 clean.id = allPosts.max(ofProperty: "id")! + 1 22 print(clean.id) 23 } 24 try! realm.write{ 25 self.clean.cleanMessage = textField.text! 26 self.clean.date = date 27 self.realm.add(self.clean, update: .modified) 28 } 29 } 30 } 31}

Swift

1class Clean: Object{ 2 @objc dynamic var id = 0 3 @objc dynamic var cleanMessage = "" 4 @objc dynamic var date = Date() 5 override static func primaryKey() -> String? { 6 return "id" 7 } 8}

試したこと

ViewWillDisappearの中でclean.idをデバッグさせました
2周目の処理(CleanViewController内のTextViewに文字を打ち込む→画面を離れデータを保存させる→再度CleanViewControllerのTextViewにテキストを入れる→画面を離れる)の際、idの最大の数に1を足す処理の前はデバッグされるのですが、その後のデバッグがされていないので、あくまでも予測なのですが、

clean.id = allPosts.max(ofProperty: "id")! + 1

この箇所に問題があるのではないかと思います

あやふやな知識で申し訳ないのですがご教授頂けますと幸いです
よろしくお願いします

補足情報(FW/ツールのバージョンなど)

Realm・Swift・Xcodeは最新バージョンです

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2022/08/24 15:41

エラーメッセージの通り、id は変更できない (というか、変更したら id の意味がない) ってことでは…。
miyuki

2022/08/24 15:56

わかりにくくてすみません。画面が更新されるたびに新しいIDになるようにその時点で最大のIDに1を足していくような仕組みにしたいということです。
hoshi-takanori

2022/08/24 22:21

CleanViewController の clean プロパティは Realm オブジェクトに見えるけど、その id を更新してるのて…。いまいち何がしたいかよく分からないコードだけど、新しい Clean オブジェクトを作りたいってこと?
miyuki

2022/08/25 04:16

そういうことです。その際のプライマリーキーとなるIDの更新がうまく行っていないです。
退会済みユーザー

退会済みユーザー

2022/08/25 13:11

> Primary key can't be changed after an object is inserted > その際のプライマリーキーとなるIDの更新 同じインスタンスでプライマリーキーを更新しようとするのは考え方が違うのかもしれませんね。 `let clean = Clean()`を`var clean: Clean?`に変更して、 viewWillAppear(_)の中で`clean = Clean()`としてみたら何か改善されますでしょうか。 CleanViewControllerの使い方によるかもしれませんが、 手元の環境で再現確認してみたところ `let clean = Clean()`のままでもエラーにはなりませんでした。 *呼び出しもとの画面から毎回CleanViewControllerのインスタンスを生成して確認しました
miyuki

2022/08/25 16:15 編集

ご回答くださりありがとうございます。ご教授いただいた通りに試してみたところ上手く行きました。本当にありがとうございます。初歩的な質問で申し訳ないのですが「プライマリーキーを更新するためにもCleanオブジェクトを画面が更新するたびに生成する必要がある」という解釈であっていますでしょうか?
退会済みユーザー

退会済みユーザー

2022/08/26 00:19

コメントありがとうございます。 > 「プライマリーキーを更新するためにもCleanオブジェクトを画面が更新するたびに生成する必要がある」という解釈であっていますでしょうか? プライマリーキー(主キー)の前提について認識合わせしておいた方が良いのかもしれないと思いました。 > Primary key values must be unique across all instances of an object in a realm. Attempting to insert a duplicate primary key value results in an error. > (機械翻訳)主キーの値は、あるレルム内のオブジェクトのすべてのインスタンスで一意でなければなりません。重複する主キー値を挿入しようとすると、エラーになります。 > > ...省略... > > Primary key values are immutable. To change the primary key value of an object, you must delete the original object and insert a new object with a different primary key value. > (機械翻訳)主キーの値は不変です。オブジェクトの主キー値を変更するには、元のオブジェクトを削除して、別の主キー値を持つ新しいオブジェクトを挿入する必要があります。 > > https://www.mongodb.com/docs/realm/sdk/kotlin/realm-database/schemas/primary-key/ --- > 主キー(しゅキー、英語:primary key)とは、 > 関係に格納されたレコードを一意に識別するための属性(列、アトリビュート)またはその集合 > https://ja.wikipedia.org/wiki/主キー --- プライマリーキーを変えたいのであれば、引用にあるように「元のオブジェクトを削除して、別の主キー値を持つ新しいオブジェクトを挿入する」ことになると思います。 一つ前の私のコメントにあるような修正内容ですと、元のオブジェクトは削除していないと思いますので、類似の?オブジェクトが増え続けることになると思います。 オブジェクトが増え(追加)続けているのに「(プライマリーキーの)更新」という言葉に違和感がありましたので、念の為書いてみました。 (これまでプログラミングをしてきた経験からですと、「更新」という言葉は同じオブジェクト(インスタンス?)の内容を変えるという印象がありましたので・・) でもこのアプリ的にオブジェクトが増えることは問題なくて、それを「(プライマリーキーの)更新」と呼ぶのでしたら、その解釈で大丈夫だと思いました。 --- > 主キーの選択 > 主キーはその関係の外部(他の関係や、外部システム、ユーザなど)で識別子として利用される確率が高いため、不変 (immutable) であるべきである。つまり、更新がかからない項目がよい。例えば、他の関係で主キーを使用していた場合、主キーを更新すると他の関係の値(外部キー)も同時に更新しなければならなくなる。また、外部システムなどに所在するデータについては、このような更新が不可能なことがありうる。なお、人工キーは通常、それ自体に意味を持たないため、不変であるから、この問題も避けることができる。 > https://ja.wikipedia.org/wiki/主キー もしオブジェクトが増えることがアプリ的に問題でしたら、プライマリーキーの設計を見直した方が良いのかもしれませんね。
miyuki

2022/08/26 08:01

ご回答くださりありがとうございます。とても丁寧に解説していただき大変勉強になりました。 >オブジェクトが増え(追加)続けているのに「(プライマリーキーの)更新」という言葉に違和感がありましたので、念の為書いてみました。 ご教授くださりありがとうございます。「プライマリーキーの更新」というよりは「ViewWillAppearで新しくオブジェクトを作成するにあたってその識別子にあたるID(=プライマリーキー)を1ずつ大きい値にしていく」ということですかね。 >でもこのアプリ的にオブジェクトが増えることは問題なくて、それを「(プライマリーキーの)更新」と呼ぶのでしたら、その解釈で大丈夫だと思いました。 オブジェクトが増えることは全く問題ないです!xg63ex2b様のご経験からもご教授いただき「更新」という単語の持つ印象も知ることができまして、非常に助かりました。本当にありがとうございます。
退会済みユーザー

退会済みユーザー

2022/08/26 11:05

コメントありがとうございます。 解消できたようでよかったです。 他に問題がないようでしたら、回答欄に自己解決の形で結果を入力しておくと良いと思います。
miyuki

2022/08/26 12:25

そうさせていただきます!ありがとうございます
guest

回答1

0

自己解決

Swift

1let clean = Clean()

の箇所を

Swift

1var clean: Clean!

に変更して、 viewWillAppear(_)の中でclean = Clean()とすることで画面が更新されるたびにCleanオブジェクトが生成され、それに伴いプライマリーキーとなっているIDの値も1つずつ増やしていくことができました。
「オブジェクトの生成」という基本的な所で抜けていたようです。
xg63ex2b様にご教授いただきました(質問のコメントを参照ください)

投稿2022/08/26 12:32

miyuki

総合スコア23

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問