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

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

ただいまの
回答率

90.53%

  • Swift

    7213questions

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

  • Swift 2

    1331questions

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

  • Realm

    196questions

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

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

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 348

beniho

score 15

 前提・実現したいこと

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

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

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

 該当のソースコード

import Foundation
import RealmSwift

@objcMembers class DayScheduled: Object {

    dynamic var date = String()
    dynamic var plans = List<OneDayScheduled>()

    // dateをプライマリキーに設定
    override static func primaryKey() -> String? {
        return "date"
    }
}

@objcMembers class OneDayScheduled: Object {

    dynamic var title = String()
    dynamic var places = List<OneDayScheduledPlace>()

    // titleをプライマリキーに設定
    override static func primaryKey() -> String? {
        return "title"
    }
}

@objcMembers class OneDayScheduledPlace: Object {
    dynamic var place = String()
}
import Foundation
import RealmSwift

class RealmSys {
    // Scheduled追加(idから)
    func addScheduled(date: String = "", title: String = "", places: [String] = []) {
        Realm.Configuration.defaultConfiguration = config
        let dayscheduled:DayScheduled = DayScheduled()
        let onedayscheduled:OneDayScheduled = OneDayScheduled()
        let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace()
        try! realm.write {
            if date != "" {
                dayscheduled.date = date
            }
            if title != "" {
                onedayscheduled.title = title
            }
            if !places.isEmpty {
                for place in places {
                    onedayscheduledplace.place = place
                    onedayscheduled.places.append(onedayscheduledplace)
                    realm.add(onedayscheduled, update: true)
                }
            }
            dayscheduled.plans.append(onedayscheduled)
            realm.add(dayscheduled, update: true)
        }
    }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

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

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

check解決した方法

0

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

import Foundation
import RealmSwift

class RealmSys {
    // Scheduled追加(idから)
    func addScheduled(date: String = "", title: String = "", places: [String] = []) {
        Realm.Configuration.defaultConfiguration = config
        let dayscheduled:DayScheduled = DayScheduled()
        let onedayscheduled:OneDayScheduled = OneDayScheduled()
        //↓こっちは削除
        //let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace()
        try! realm.write {
            if date != "" {
                dayscheduled.date = date
            }
            if title != "" {
                onedayscheduled.title = title
            }
            if !places.isEmpty {
                for place in places {
            //↓こっちに追加
                    let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace()
                    onedayscheduledplace.place = place
                    onedayscheduled.places.append(onedayscheduledplace)
                    realm.add(onedayscheduled, update: true)
                }
            }
            dayscheduled.plans.append(onedayscheduled)
            realm.add(dayscheduled, update: true)
        }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/01 00:54 編集

    一番下に投稿させていただきましたが、primaryKeyは重複できないので、
    重複check機能が必要になります。

    また、onedayshceduledplaceはデータベースに登録されていませんが。。。
    それはそれでいいのでしょうか?

    さらに、余計かもしれませんが、日付はStringで保存せず、
    Date型にした方が他のクラスを使いやすくないですか?
    自前で入力checkや並び替え、月に条件を絞った検索など実現に
    一手間増える事になってしまいそうです。
    また、エラーを避ける意味でも、
    ない日付をアラートするとかの実装も結構な手間になりそうです。
    (String→Date型に変換するからいいよって言えば、それまでですが、、、)

    そして、dateとdateのように変数や定数に同じ文字列を使うと
    どっちがどっちを表しているのかわかりづらいので、
    c_date(current)やr_date(received)、何でもいいんですが
    分けた方が見直す時に見やすいし、検索もかけやすいので
    利点があると思います。

    最後に配列チェックも登録する際にはねればいいかもしれませんが、
    ["", "", ""]のような空白の配列もisEmptyや.count == 0ではスルーしてしまいますので、
    追加コードが必要になります。考えてみて下さい。

    口うるさくすいませんでした、、、
    それではお互いいいアプリ作れるように頑張りましょう。

    キャンセル

0

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

print("placesには", places.count, "個データがあります。") // ※

for place in places {
print("placeは", place, "です。")
onedayscheduledplace.place = place
onedayscheduled.places.append(onedayscheduledplace)
realm.add(onedayscheduled, update: true)
print("onedayscheduledは", onedayscheduled)
print("dayscheduled.plansは", dayscheduled.plans)

}


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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/30 22:35

    dayscheduled.plans.append(onedayscheduled)をfor文の中に入れましたが、
    結果は変わりませんでした。

    何か他に問題があるのでしょうか?

    キャンセル

  • 2018/05/30 23:59 編集

    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への登録の仕方のどこかに問題ありです。

    キャンセル

  • 2018/05/31 22: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に保存されておりました。

    仰る通り登録の仕方に問題があるかもしれません。

    キャンセル

0

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

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

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

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

そこを踏まえ書くと、

    class RealmSys {
        // Scheduled追加(idから)
        func addScheduled(date: String = "", title: String = "", places: [String] = []) {
            if date == "" || title == "" || places.count == 0 {
                return
            } else {
                Realm.Configuration.defaultConfiguration = config

                // まず全体から入力日付と同じ日の存在を検索し、一致するデータをセット
                let sameDay = NSPredicate(format: "date = %@", date)
                let matchedDayScheduled = realm.objects(DayScheduled.self).filter(sameDay)

                // 変数でDayScheduledを作成し重複あれば、過去のをセットする
                var cDayScheduled:DayScheduled = DayScheduled()
                if matchedDayScheduled.count > 0 {
                    print("Matched data exists.")
                    cDayScheduled = matchedDayScheduled.first // 複数ないけど、1個目を指定…記述上必要
                }

                let onedayscheduled = OneDayScheduled()
                try! realm.write {
                    // まずonedaysscheduledplaceを作成
                    for place in places {
                        print("Place is:", place)
                        let onedayscheduledplace:OneDayScheduledPlace = OneDayScheduledPlace()
                        onedayscheduledplace.place = place
                        realm.add(onedayscheduledPlace)
                        onedayscheduled.places.append(onedayscheduledplace)
                        print("Added onedaysscheduledplace:", onedayscheduledplace)
                    }
                    onedayscheduled.title = title
                    realm.add(onedayscheduled, update: true)
                    print("Added OneDayScheduled:", onedayscheduled)
                    cDayScheduled.date = date
                    cDayScheduled.plans.append(onedayscheduled)
                    realm.add(cDayScheduled, update: true)
                    print("Total cDayScheduled:", cDayScheuled)
                }
            }
        }
    }

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

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

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

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    Swift2 RealmオブジェクトをJSON形式に変換する方法

    Swift2でRealmデータベースを使っています。 PHPとのデータのやり取りをJSON形式で行いたいと思っています。 PHP -> Swiftは特に問題なく行えました。

  • 解決済

    RealmSwiftでマイグレーションを実装したい

    前提・実現したいこと SwiftでRealmSwiftのマイグレーションを実装したいと思っています。Realmの公式のドキュメントを参考に以下のコードを書いたのですが、マイグレー

  • 解決済

    RLMArray に Object をappendしたい

    PersonクラスとしてRealmオブジェクトとして以下のようなものを定義していて、APIサーバーからPersonにデータをmappingさせて利用しています。 class

  • 解決済

    RealmSwiftについて質問です。

    swiftでRealmSwiftについて質問です。 以下のようなエラーが出るのですが、解決法がわかりません。 どのようにすれば良いのか教えていただけるの幸いです。

  • 解決済

    RealmSwiftで特定日付のデータを抽出する方法を知りたい

    前提・実現したいこと 初心者です。 Realmに登録したDate()のデータから日付を指定して抽出・表示したいのですが、よくわからず立ち止まっています。 よろしくお願いします

  • 解決済

    swift realm xcode

    現在、UserDefaultsを使ってテキストに入力した文字をラベルに反映させ、保存するという単純なものを作りましたが。これをRealmを使って同じようにさせたいのですが、本日使い

  • 解決済

    RealmSwiftで複数のclassを一つのListで保存したい。

    現在、ユーザーの複数のSNSアカウントを管理するアプリを制作しています。 その中で、登録された複数のSNSアカウントの情報からユーザーが選択したアカウントだけを一つのListにまと

  • 解決済

    RealmSwiftについて

    import UIKit import RealmSwift class CellData { var title: String = "" var detail

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

  • Swift

    7213questions

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

  • Swift 2

    1331questions

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

  • Realm

    196questions

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