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

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

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

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

Swift

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

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

解決済

3回答

1519閲覧

Realmに連続してデータを追加する

shi_o

総合スコア53

Realm

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

Swift

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

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

0クリップ

投稿2018/05/29 14:20

前提・実現したいこと

配列を引数に渡してfor文で配列の中にある全データをRealmに保存したいです。

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

一番最後の値のみ追加される

該当のソースコード

swift

1import Foundation 2import RealmSwift 3 4@objcMembers class DayScheduled: Object { 5 6 dynamic var date = String() 7 dynamic var plans = List<OneDayScheduled>() 8 9 // dateをプライマリキーに設定 10 override static func primaryKey() -> String? { 11 return "date" 12 } 13} 14 15@objcMembers class OneDayScheduled: Object { 16 17 dynamic var title = String() 18 dynamic var places = List<OneDayScheduledPlace>() 19 20 // titleをプライマリキーに設定 21 override static func primaryKey() -> String? { 22 return "title" 23 } 24} 25 26@objcMembers class OneDayScheduledPlace: Object { 27 dynamic var place = String() 28}

swift

1import Foundation 2import RealmSwift 3 4class RealmSys { 5 // Scheduled追加(idから) 6 func addScheduled(date: String = "", title: String = "", places: [String] = []) { 7 Realm.Configuration.defaultConfiguration = config 8 let dayscheduled:DayScheduled = DayScheduled() 9 let onedayscheduled:OneDayScheduled = OneDayScheduled() 10 let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace() 11 try! realm.write { 12 if date != "" { 13 dayscheduled.date = date 14 } 15 if title != "" { 16 onedayscheduled.title = title 17 } 18 if !places.isEmpty { 19 for place in places { 20 onedayscheduledplace.place = place 21 onedayscheduled.places.append(onedayscheduledplace) 22 realm.add(onedayscheduled, update: true) 23 } 24 } 25 dayscheduled.plans.append(onedayscheduled) 26 realm.add(dayscheduled, update: true) 27 } 28 } 29}

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

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

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

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

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

guest

回答3

0

そのConsoleの様子だと、
forを回すごとに、登録はできている
(Placesの個数がちゃんと増えている)
しかし、毎回、Placesの要素であるplaceが最後の要素に置き換えられている
ということがわかります。

forの回し方に問題がありそうだなと思って、
詳細にコードを見させていただいたところ、、、

実は、Realm Objectの作成の仕方に問題があることに気づきました。
OneDayScheduledPlaceはplacesの個数分作成しないといけませんよね?
ということは毎回新たなOneDayScheduledPlaceを作成しないといけません。
最初にlet onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace()
で 1個しか作ってないところは間違いになります。

また、DaysScheduledのdateはPrimary Keyに設定されてるので、重複はダメということになります。
つまり毎回先に登録されていないか検索する必要が出てきます。
そして、存在すれば、それをセット、なければ新規作成することになります。

そこを踏まえ書くと、

Swift

1 class RealmSys { 2 // Scheduled追加(idから) 3 func addScheduled(date: String = "", title: String = "", places: [String] = []) { 4 if date == "" || title == "" || places.count == 0 { 5 return 6 } else { 7 Realm.Configuration.defaultConfiguration = config 8 9 // まず全体から入力日付と同じ日の存在を検索し、一致するデータをセット 10 let sameDay = NSPredicate(format: "date = %@", date) 11 let matchedDayScheduled = realm.objects(DayScheduled.self).filter(sameDay) 12 13 // 変数でDayScheduledを作成し重複あれば、過去のをセットする 14 var cDayScheduled:DayScheduled = DayScheduled() 15 if matchedDayScheduled.count > 0 { 16 print("Matched data exists.") 17 cDayScheduled = matchedDayScheduled.first // 複数ないけど、1個目を指定…記述上必要 18 } 19 20 let onedayscheduled = OneDayScheduled() 21 try! realm.write { 22 // まずonedaysscheduledplaceを作成 23 for place in places { 24 print("Place is:", place) 25 let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace() 26 onedayscheduledplace.place = place 27 realm.add(onedayscheduledPlace) 28 onedayscheduled.places.append(onedayscheduledplace) 29 print("Added onedaysscheduledplace:", onedayscheduledplace) 30 } 31 onedayscheduled.title = title 32 realm.add(onedayscheduled, update: true) 33 print("Added OneDayScheduled:", onedayscheduled) 34 cDayScheduled.date = date 35 cDayScheduled.plans.append(onedayscheduled) 36 realm.add(cDayScheduled, update: true) 37 print("Total cDayScheduled:", cDayScheuled) 38 } 39 } 40 } 41 }

これで大丈夫だと思います。
printで各所でコンソール出力も入れているので試して見てください。
スペルミスはあるかもしれませんが、その際はご容赦ください。

投稿2018/05/31 15:46

hameji

総合スコア1380

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

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

0

自己解決

下記のようにfor文で一回一回初期化したら狙った結果になりました。

swift

1import Foundation 2import RealmSwift 3 4class RealmSys { 5 // Scheduled追加(idから) 6 func addScheduled(date: String = "", title: String = "", places: [String] = []) { 7 Realm.Configuration.defaultConfiguration = config 8 let dayscheduled:DayScheduled = DayScheduled() 9 let onedayscheduled:OneDayScheduled = OneDayScheduled() 10 //↓こっちは削除 11 //let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace() 12 try! realm.write { 13 if date != "" { 14 dayscheduled.date = date 15 } 16 if title != "" { 17 onedayscheduled.title = title 18 } 19 if !places.isEmpty { 20 for place in places { 21            //↓こっちに追加 22 let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace() 23 onedayscheduledplace.place = place 24 onedayscheduled.places.append(onedayscheduledplace) 25 realm.add(onedayscheduled, update: true) 26 } 27 } 28 dayscheduled.plans.append(onedayscheduled) 29 realm.add(dayscheduled, update: true) 30 } 31 } 32}

投稿2018/05/31 15:12

shi_o

総合スコア53

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

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

hameji

2018/05/31 16:06 編集

一番下に投稿させていただきましたが、primaryKeyは重複できないので、 重複check機能が必要になります。 また、onedayshceduledplaceはデータベースに登録されていませんが。。。 それはそれでいいのでしょうか? さらに、余計かもしれませんが、日付はStringで保存せず、 Date型にした方が他のクラスを使いやすくないですか? 自前で入力checkや並び替え、月に条件を絞った検索など実現に 一手間増える事になってしまいそうです。 また、エラーを避ける意味でも、 ない日付をアラートするとかの実装も結構な手間になりそうです。 (String→Date型に変換するからいいよって言えば、それまでですが、、、) そして、dateとdateのように変数や定数に同じ文字列を使うと どっちがどっちを表しているのかわかりづらいので、 c_date(current)やr_date(received)、何でもいいんですが 分けた方が見直す時に見やすいし、検索もかけやすいので 利点があると思います。 最後に配列チェックも登録する際にはねればいいかもしれませんが、 ["", "", ""]のような空白の配列もisEmptyや.count == 0ではスルーしてしまいますので、 追加コードが必要になります。考えてみて下さい。 口うるさくすいませんでした、、、 それではお互いいいアプリ作れるように頑張りましょう。
guest

0

デバックを自分でしてみて、確認してみてはどうでしょうか。
そうすれば、今後もエラーが出た際に自分で解決できるようになると思います。
簡単なことをミスってるだけかもしれませんし。

Swift

1print("placesには", places.count, "個データがあります。") // ※ 2 3for place in places { 4print("placeは", place, "です。") 5onedayscheduledplace.place = place 6onedayscheduled.places.append(onedayscheduledplace) 7realm.add(onedayscheduled, update: true) 8print("onedayscheduledは", onedayscheduled) 9print("dayscheduled.plansは", dayscheduled.plans) 10 11}

とすれば、どのタイミングで何が、どう動いてるのか、自分でわかると思います。
printは便利なので、ぜひ使いこなせるようなるといいとお思います。

と書いたところで、気づいたのですが、各onedayscheduledのみforで回してて、
肝心のdayscheduled.plansがfor文の外なので、
最後の1回しか登録されないんだと思います。

投稿2018/05/29 16:20

hameji

総合スコア1380

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

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

shi_o

2018/05/30 13:35

dayscheduled.plans.append(onedayscheduled)をfor文の中に入れましたが、 結果は変わりませんでした。 何か他に問題があるのでしょうか?
hameji

2018/05/30 15:00 編集

printは試されたのでしょうか? データ本体がなく、こちらで試すことはできないので、 なかなかどこに問題があるのか指摘しずらいです。 dayscheduled.plans.append(onedayscheduled) realm.add(dayscheduled, update: true) 両方とも入れましたか? dataのplacesの個数は何個なのかわかりませんが、 for place in places { } の中に、 let totalSchedule = try! Realm().objects(dayscheduled.self) print("いまのRealmに保存されてるのは", totalSchedule) と記載して、確認してください。 forを回してる時に1個1個登録されてないなら、 realmへの登録の仕方のどこかに問題ありです。
shi_o

2018/05/31 13:23

dayscheduled.plans.append(onedayscheduled) realm.add(dayscheduled, update: true) 両方とも入れました。 places = RLMArray<OneDayScheduledPlace> <0x6000001076b0> ( [0] OneDayScheduledPlace { place = aaa; } ); ↓ places = RLMArray<OneDayScheduledPlace> <0x60c00010ab90> ( [0] OneDayScheduledPlace { place = bbb; }, [1] OneDayScheduledPlace { place = bbb; } ); ↓ places = RLMArray<OneDayScheduledPlace> <0x60c000109ab0> ( [0] OneDayScheduledPlace { place = ccc; }, [1] OneDayScheduledPlace { place = ccc; }, [2] OneDayScheduledPlace { place = ccc; } ); 上記のようにRealmに保存されておりました。 仰る通り登録の仕方に問題があるかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問