Codableで型を保ったままUserDefaultsに保存する

UserDefaultsはちょっとしたデータ保存に便利です。

保存するときStructClassをそのまま保存できれば便利ではないですか?

それができるのです。

UserDefaultsData型を保存可能です。

また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に保存する方法を解説しました。

型情報があるととても便利です。

ぜひ使ってみてください。