Swift 4 から Codable
が使えるようになったので活用しましょう。
UserDefaults
に struct
は保存できませんが String
は保存できるので、
Codable
を適用することで、
struct
から JSON(String)
に変換(エンコード)して保存
JSON(String)
から struct
に変換(デコード)して取得
というイメージです。
コード
扱う Struct
Codable
を適用します。
struct Person: Codable {
let name: String
let age: Int
}
用意した Extension
直で書いてもいいですが、少し便利になるよう用意しました。
try?
とかで適当に書いちゃってるのでエラーハンドリングなどどうぞ。
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
}
}
2020.02.23 追記
@nak435 @p_x9 さんのコメントより、ループするとのご指摘をいただき、コードを修正いたしました。
詳しくはコメントをご参照ください。お二方ありがとうございます!
2020.11.30 追記
set(_ value: Codable?, forKey key: String)
→ setCodable(_ value: Codable?, forKey key: String)
へと変更しました。
コードコメントをご確認ください。
UserDefaults に保存 / から取得
let persons = [Person(name: "Sato Taro", age: 20), Person(name: "Ito Hanako", age: 10)]
// 保存
UserDefaults.standard.set(persons, forKey: "person")
// 取得
let restoredPersons: [Person]? = UserDefaults.standard.codable(forKey: "person")
// 出力
print(restoredPersons!)
// [TempProject.Person(name: "Sato Taro", age: 20), TempProject.Person(name: "Ito Hanako", age: 10)]
環境
- Swift 5