【Swift】UserDefaultに非対応のデータを保存する
どうも、ねこきち(@nekokichi1_yos2)です。
今回は、UserDefaultでAny型に含まれる、UserDefaultには非対応のデータを扱う方法を書いていきます。
解説
Any型で保存できないの?
一部のデータは保存できました。
例えば、普通の辞書や配列は問題ありませんでした。
// [String] UserDefaults.standard.set(["gsgs","gs","56252"], forKey: "array") // [String : Array] UserDefaults.standard.set(["color":[2,3,4], "afa":[2,5,2]], forKey: "array") // [String : [String : Int]] UserDefaults.standard.set(["dic1":["2":2],"dic2":["1":1]], forKey: "array")
しかし、UILabelの配列や、異なる型を格納した辞書だと、エラーが出ます。
let dic:[String:Any] = [ "color":UIColor.red, "bool":bool ] UserDefaults.standard.set(dic, forKey: "color_bool")
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object {
bool = 1;
color = "UIExtendedSRGBColorSpace 1 0 0 1";
} for key color_bool'
残念ながら、Any型でも、あらゆるデータを保存することはできないようです。
じゃあどうするか、Data型に変換すれば良いのです。
Data型に変換して、Data型から元の型に戻す
Data型への変換は、NSKeyedArchiver.archivedData、を使用します。
(requiringSecureCodingの値は、true,false、のどちらでも問題ありません。)
let data:Data = try! NSKeyedArchiver.archivedData(withRootObject: 保存したいデータ, requiringSecureCoding: false)
そして、保存したデータを取り出す際は、NSKeyedArchiver.unarchiveTopLevelObjectWithData、で取り出します。
(変数に入れる場合、型を指定する必要があります。)
if let data = UserDefaults.standard.data(forKey: "キー") { let dic = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [String:Any]
let text = dic["bool"] as! Bool
}
結果
ソースコード
import UIKit class ViewController2: UIViewController { @IBOutlet weak var label: UILabel! @IBAction func display(_ sender: Any) { if let data = UserDefaults.standard.data(forKey: "color_bool") { let dic = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [String:Any] let text = dic["bool"] as! Bool label.text = "\(text)" label.backgroundColor = dic["color"] as! UIColor } } @IBAction func red(_ sender: Any) { setData(.red, true) } @IBAction func blue(_ sender: Any) { setData(.systemBlue, false) } @IBAction func yellow(_ sender: Any) { setData(.yellow, true) } func setData(_ color:UIColor, _ bool:Bool) { let dic:[String:Any] = [ "color":color, "bool":bool ] let data:Data = try! NSKeyedArchiver.archivedData(withRootObject: dic, requiringSecureCoding: false) UserDefaults.standard.set(dic, forKey: "color_bool") } }
参考