【Swift】Core DataのエンティティをJSONに変換(エンコード/デコード)する方法!
この記事からわかること
- SwiftでCore DataのエンティティをJSONに変換する方法
- エンコード/デコードするには?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.0
- Swift:5.9
- macOS:Sonoma 14.1
Core DataのエンティティをJSON形式に変換する方法
Core DataのエンティティクラスをJSON形式にエンコード/デコードするにはデコードする際にNSManagedObjectContext
を利用する必要があります。これをしないとエラーになってしまいデコードできませんでした。エンコードは特に問題なくJSON文字列に変換することができるので相互に変換しない場合は気にしなくもて大丈夫でした。
これはそもそもエンティティクラスであるNSManagedObject
をインスタンス化する際にはNSManagedObjectContext
が必要であり、そのままではインスタンス化できないためです。以下記事の手順で「エンティティクラス+CoreDataClass.swift
」ファイルを作成し、エンティティクラスをEncodable
とDecodable
に準拠させていきます。
ポイントとなるのはdecoder
のuserInfo
からNSManagedObjectContext
を取得してイニシャライザを実行しているところです。コンテキストは後で格納する部分の処理を記述します。
@objc(Company)
public class Company: NSManagedObject, Encodable, Decodable {
enum CodingKeys: CodingKey {
case id, name, location
}
convenience init(id: UUID, name: String, location: String) {
self.init()
self.id = id
self.name = name
self.location = location
}
public 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)
try container.encode(location, forKey: .location)
}
required public convenience init(from decoder: Decoder) throws {
// CoreDataをJSONにデコードするにはuserInfoからcontextを取得する
guard let context = decoder.userInfo[CodingUserInfoKey(rawValue: "context")!] as? NSManagedObjectContext else { fatalError() }
self.init(context: context)
let container = try decoder.container(keyedBy: CodingKeys.self)
self.id = try container.decode(UUID.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.location = try container.decode(String.self, forKey: .location)
}
}
JSONに変換するための処理をクラスに切り出しておきます。ここでのポイントはuserInfo
のCodingUserInfoKey(rawValue: "context")
キーにNSManagedObjectContext
を格納します。ここで指定するキーはrequired public convenience init(from decoder: Decoder)
内で指定したキー名と同じにしておきます。
class JsonConverter {
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()
public func decode(_ json: String) -> [Company]? {
guard let jsonData = String(json).data(using: .utf8) else { return nil }
// 使用しているコンテキストを格納する
decoder.userInfo[CodingUserInfoKey(rawValue: "context")!] = MainCoreDataRepository.shared.viewContext
guard let companys = try? decoder.decode([Company].self, from: jsonData) else { return nil }
return companys
}
public func encode(_ data: [Company]) -> String? {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
guard let jsonData = try? encoder.encode(data) else { return nil }
guard let json = String(data: jsonData , encoding: .utf8) else { return nil }
return json
}
}
あとはJsonConverter
を使用して変換すればOKです。
let jsonConverter = JsonConverter()
guard let json = jsonConverter.encode(companys) else { return }
print(json)
guard let companys = jsonConverter.decode(json) else { return }
print(companys)
この実装はGitHubにも挙げているので参考にしてください。
おすすめ記事:GitHub-MyCoreDataTest
ご覧いただきありがとうございました。