NSCoding意味わかんない
意味分かんない
UserDefaultsに保存できるデータ型
UserDefaultsに保存できるデータ型は
数値型
文字列型
真偽型
データ型(Data、NSData)
とこれらを値とする
配列型
辞書型(キーは文字列型に限る)
のみとなっています。
非対応のデータ型を保存する方法 その1
保存できるデータ型(Data,NSDataを除く)に変換する。
例えば CGRect を数値の配列に変換して保存するなどです。
extension UserDefaults {
func set(_ value: CGRect, forKey key: String) {
let rectDataArray = [value.origin.x, value.origin.y, value.width, value.height]
set(rectDataArray, forKey: key)
}
func cgRect(forKey key: String) -> CGRect? {
guard let rectDataArray = array(forKey: key) as? [CGFloat] else { return nil }
guard rectDataArray.count == 4 else { return nil }
return CGRect(x: rectDataArray[0], y: rectDataArray[1], width: rectDataArray[2], height: rectDataArray[3])
}
}
非対応のデータ型を保存する方法 その2
その1で数値や文字列にするのが難しいデータ型の場合はデータ(NSData/Data)に変換して保存します。
その助けをするのがNSCodingプロトコルとNSKeyedArchiver/NSKeyedUnarchiverです。
これをやりたくない趣旨のエントリですので詳細は省きます。
非対応のデータ型を保存する方法 その3
実はSwiftにはNSCodingを使わなくてもデータ型をデータ(NSData/Data)に簡単に変換してもらえる便利なものがあります。
Codable = Encodable & Decodable
です。
Codableへの準拠は変わったデータ型ではない限り、コンパイラが自動で行ってくれるのがすごくうれしい!
これを使わない手はありません。
ここではCoderとしてJSON(En/De)coderを使用しました。
extension UserDefaults {
func setEncoded<T: Encodable>(_ value: T, forKey key: String) {
guard let data = try? JSONEncoder().encode(value) else {
print("Can not Encode to JSON.")
return
}
set(data, forKey: key)
}
func decodedObject<T: Decodable>(_ type: T.Type, forKey key: String) -> T? {
guard let data = data(forKey: key) else {
return nil
}
return try? JSONDecoder().decode(type, from: data)
}
}
CGRectを保存してみましょう。
CGRectはCodableに準拠してますので特に何か付け加える必要はありません。
let cgRect = CGRect(x: 0, y: 0, width: 100, height: 100)
UserDefaults.standard.setEncoded(cgRect, forKey: "KEY")
// storedCGRect's type is CGRect.
let storedCGRect = UserDefaults.standard.decodedObject(CGRect.self, forKey: "KEY")
はい、簡単、型安全。
とくにまとめることはない
簡単さと標準準拠を肝としたのでUserDefaultsのKeyがStringで危険なままですが、そのあたりは別にいろいろあるのでググったりなんだりすればいいと思う。