💡

先駆者様の便利すぎるStruckのEncode/Decodableの拡張が便利すぎるから広めたい。

2022/04/16に公開

はじめに

まず記事を紹介します。こちらの記事だけでも十分実装できますが、ハマりそうなポイントなどは紹介します。

https://qiita.com/yuki0n0/items/280e351f85c502945d06

紹介したい点が強いので、ほぼ引用の記事ですが、利点など述べています。
元記事必ずアクセスして欲しいです。

なにが優れているのか

以前のやり方だと以下のようにCodingKeyを記載してあげたりする必要がありました。

import Foundation

struct Coordinate: Codable {
    var latitude: Double
    var longitude: Double
    var elevation: Double = 0 // default value

    enum CodingKeys: String, CodingKey {
        case latitude = "another_key"
        case longitude
    }
}

つまり、Codableを継承したStructを都度編集する必要性が生じました。
この記事の方法ではEncodableDecodableを拡張しているので、各自のStructクラスで処理を記載しなくていいのです。これってかなり良くないですか!?

不要な作業がいらないんです。

できるようになること

struct(構造体)を大きく編集せずに、アーカイブすることができる。
UserDefaultsなどでアーカイブ/アンアーカイブできる。
そのまま保存できます。

記載する処理

Extension.swiftなど作成

以下を記載します。

extension Encodable {

    var json: Data? {
        let encoder = JSONEncoder()
        return try? encoder.encode(self)
    }
}

extension Decodable {

    static func decode(json data: Data?) -> Self? {
        guard let data = data else { return nil }
        let decoder = JSONDecoder()
        return try? decoder.decode(Self.self, from: data)
    }
}

extension UserDefaults {

    /// - Warning:
    /// 2020.11.30追記) setCodable ではなく set という関数名にすると、String をセットしたいときに Codable と衝突して Codable 扱いとなってしまうため注意。
    func setCodable(_ value: Codable?, forKey key: String) {
        guard let json: Any = value?.json else { return } // 2020.02.23 追記参照
        self.set(json, forKey: key)
        synchronize()
    }

    func codable<T: Codable>(forKey key: String) -> T? {
        let data = self.data(forKey: key)
        let object = T.decode(json: data)
        return object
    }
}

保存する処理


// 元記事さんはこのように書かれていますが独自のStructを用意できればいいです。
let persons = [Person(name: "Sato Taro", age: 20), Person(name: "Ito Hanako", age: 10)]

// 保存
UserDefaults.standard.setCodable(persons, forKey: "person")

// 取得
let restoredPersons: [Person]? = UserDefaults.standard.codable(forKey: "person")

// 出力  
print(restoredPersons!)

ちなみにUserDefaults.standard.setCodable(persons, forKey: "person")と書かないとエラーになるので注意。元記事でも触れていますが、Swiftの予約語のsetと競合しちゃうんですよねー。

Discussion