【Swift】RealmのDBから取得したデータをJSONに変換する際の注意点
この記事からわかること
- Realmで保存したデータをJSONに変換する方法
- エンコードできない場合の対処法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.0
- Realm:10.42.1
- Swift:5.9
- macOS:Sonoma 14.1
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)
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。