【Swift】RealmのDBから取得したデータをJSONに変換する際の注意点

この記事からわかること

  • Realm保存したデータJSON変換する方法
  • エンコードできない場合の対処

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

RealmのDBから取得したデータをJSONに変換する際の注意点

ローカルデータベースにRealmを採用したiOSアプリの開発で以下のような保存するモデルクラスを定義している場合に、DBから取得したRealmデータオブジェクトをJSONに変換したかったのですがうまく変換することができませんでした。

class User: Object, ObjectKeyIdentifiable, Codable {
    @Persisted(primaryKey: true) var id: ObjectId
    @Persisted var name: String = ""
}
// Realmオブジェクト出力
User {
	id = 65450be4db15c816fe20e852;
	name = ame;
}

// 以下のように変換したい。

// JSON形式で出力
{
  "id" : "65450be4db15c816fe20e852",
  "name" : "ame"
}

JSONに変換するためにはJSONEncoderを使用して以下のように実装しています。

おすすめ記事:【Swift】JSONデータをエンコードする方法!JSONEncoderクラスの使い方

struct ContentView: View {
    
    private let realm = try! Realm()
    
    public func createUser() {
        try! realm.write {
            let user = User()
            user.name = "ame"
            realm.add(user)
        }
    }
    var body: some View {
        VStack {
            Button(action: {
                try! realm.write {
                    var users = realm.objects(User.self)
                    if let user = users.first {
                        let encoder = JSONEncoder()
                        encoder.outputFormatting = .prettyPrinted
                        if let jsonData = try? encoder.encode(user) {
                            print(String(data: jsonData , encoding: .utf8)!)
                        }
                    }
                }
            }, label: {
                Text("encode")
            })
            
            Button {
                createUser()
            } label: {
                Text("Create")
            }
        }.padding()
    }
}

実装的には別におかしなところは見当たらないと思うのですが、let jsonData = try? encoder.encode(user)の部分でエンコードが成功せずにnilが返ってしまいます。

RealmのDBに保存前のRealmデータオブジェクトであれば正常に変換することが可能だったのでどうやらDBから取得したものを直接JSONに変換することはできないようです。thawで解凍などしてみましたが変わりませんでした。

public func encodeTest() {
    let user = User()
    user.name = "ame"
    let encoder = JSONEncoder()
    encoder.outputFormatting = .prettyPrinted
    if let jsonData = try? encoder.encode(user) {
        print(String(data: jsonData , encoding: .utf8)!)
    }
}

// 出力
{
  "id" : "654876d4ad9a944a4d8dad0f",
  "name" : "ame"
}

解決方法

詳しい原因はわかりませんでしたが、結果JSON型に無事変換できるようになったのは明示的に変換するキーや過程を実装した時でした。とりあえずJSONに変換できるようにはなりましたが、スッキリはしていないので誰か知っていたら教えていただけると幸いです。

class User: Object, ObjectKeyIdentifiable, Codable {
    @Persisted(primaryKey: true) var id: ObjectId
    @Persisted var name: String = ""
    
    enum CodingKeys: String, CodingKey {
        case id, name
    }

    convenience init(id: ObjectId, name: String) {
        self.init()
        self.id = id
        self.name = name
    }

    required convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(ObjectId.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(name, forKey: .name)
    }
}

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

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

searchbox

スポンサー

ProFile

ame

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

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

New Article

index