UserDefaults
はちょっとしたデータ保存に便利です。
保存するときStruct
やClass
をそのまま保存できれば便利ではないですか?
それができるのです。
UserDefaults
はData型
を保存可能です。
またStruct、ClassをSwift 4から導入されたCodableプロトコルに準拠すれば、Data型にエンコードできます。
これを組み合わせることで、型をまるごと保存することが可能です。
開発環境
- Xcode 10.1
- Swift 4.2
ソースの全体像
import Foundation
protocol Storable {
func data(forKey: String) -> Data?
func set(_ data :Any?, forKey: String)
}
// テスト用スタブのため
extension UserDefaults: Storable{}
// 責務:データの永続化
struct StoreManager {
let store: Storable
init(store: Storable = UserDefaults.standard) {
self.store = store
}
func save<T: Codable>(value: T, key: String) throws {
do {
let encodedData = try JSONEncoder().encode(value)
store.set(encodedData, forKey: key)
} catch let error {
throw error
}
}
func load<T: Codable>(key: String) -> T? {
guard let data = store.data(forKey: key) else { return nil }
do {
let decode = try JSONDecoder().decode(T.self, from: data)
return decode
} catch let error {
print(error.localizedDescription)
return nil
}
}
}
解説 データの保存
func save<T: Codable>(value: T, key: String) throws {
do {
let encodedData = try JSONEncoder().encode(value)
store.set(encodedData, forKey: key)
} catch let error {
throw error
}
}
のlet encodedData = try JSONEncoder().encode(value)
にてCodableに準拠した型をData型に変換しています。
そしてstore.set(encodedData, forKey: key)
でUserDefaultsに保存をしています。
解説 データの読み出し
func load<T: Codable>(key: String) -> T? {
guard let data = store.data(forKey: key) else { return nil }
do {
let decode = try JSONDecoder().decode(T.self, from: data)
return decode
} catch let error {
print(error.localizedDescription)
return nil
}
}
guard let data = store.data(forKey: key) else { return nil }
でUserDefaultsからData型を読み出します。
let decode = try JSONDecoder().decode(T.self, from: data)
で読み出したData型をデコードします。
まとめ
Codableに準拠したインスタンスをUserDefaultsに保存する方法を解説しました。
型情報があるととても便利です。
ぜひ使ってみてください。