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

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

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

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

Xcode

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

Swift

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

解決済

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

miyuki
miyuki

総合スコア15

Realm

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

Xcode

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

Swift

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

1回答

0リアクション

0クリップ

242閲覧

投稿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

class CleanViewController: UIViewController { @IBOutlet weak var textField: UITextField! let realm = try! Realm() let clean = Clean() var postResults = try! Realm().objects(Post.self).sorted(byKeyPath: "date", ascending: false) override func viewWillAppear(_ animated: Bool) { textField.text = "" } override func viewDidLoad() { super.viewDidLoad() } override func viewWillDisappear(_ animated: Bool) { let date = Date() if textField.text!.isEmpty == false { let allPosts = realm.objects(Clean.self) if allPosts.count != 0{ print(clean.id) clean.id = allPosts.max(ofProperty: "id")! + 1 print(clean.id) } try! realm.write{ self.clean.cleanMessage = textField.text! self.clean.date = date self.realm.add(self.clean, update: .modified) } } } }

Swift

class Clean: Object{ @objc dynamic var id = 0 @objc dynamic var cleanMessage = "" @objc dynamic var date = Date() override static func primaryKey() -> String? { return "id" } }

試したこと

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

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

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

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

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

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

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

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の更新がうまく行っていないです。
xg63ex2b

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オブジェクトを画面が更新するたびに生成する必要がある」という解釈であっていますでしょうか?
xg63ex2b

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様のご経験からもご教授いただき「更新」という単語の持つ印象も知ることができまして、非常に助かりました。本当にありがとうございます。
xg63ex2b

2022/08/26 11:05

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

2022/08/26 12:25

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

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Realm

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

Xcode

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

Swift

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