【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
}

 

結果

 

f:id:nekokichi_yos2:20200801101922g:plain


 

 

ソースコード

 

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")
    }
    
}

 

参考

 

 

stackoverflow.com

qiita.co

stackoverflow.com