【Swift】Core DataのエンティティをJSONに変換(エンコード/デコード)する方法!

この記事からわかること

  • SwiftCore DataエンティティJSON変換する方法
  • エンコード/デコードするには?

index

[open]

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

みんなの誕生日

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

posted withアプリーチ

環境

Core DataのエンティティをJSON形式に変換する方法

Core DataのエンティティクラスをJSON形式にエンコード/デコードするにはデコードする際にNSManagedObjectContextを利用する必要があります。これをしないとエラーになってしまいデコードできませんでした。エンコードは特に問題なくJSON文字列に変換することができるので相互に変換しない場合は気にしなくもて大丈夫でした。

これはそもそもエンティティクラスであるNSManagedObjectをインスタンス化する際にはNSManagedObjectContextが必要であり、そのままではインスタンス化できないためです。以下記事の手順で「エンティティクラス+CoreDataClass.swift」ファイルを作成し、エンティティクラスをEncodableDecodableに準拠させていきます。

ポイントとなるのはdecoderuserInfoから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に変換するための処理をクラスに切り出しておきます。ここでのポイントはuserInfoCodingUserInfoKey(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

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

searchbox

スポンサー

ProFile

ame

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

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

New Article

index