💡
先駆者様の便利すぎるStruckのEncode/Decodableの拡張が便利すぎるから広めたい。
はじめに
まず記事を紹介します。こちらの記事だけでも十分実装できますが、ハマりそうなポイントなどは紹介します。
紹介したい点が強いので、ほぼ引用の記事ですが、利点など述べています。
元記事必ずアクセスして欲しいです。
なにが優れているのか
以前のやり方だと以下のように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
を都度編集する必要性が生じました。
この記事の方法ではEncodable
とDecodable
を拡張しているので、各自の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