Search code examples
swiftxcodensuserdefaultsnsdata

Saving nested dictionary into UserDefaults using Xcode and Swift


I'm trying to save a nested dictionary in userDefaults. The app crashes when I try to save it the usual way, i.e.

defaults.set(totalBuy, forKey: "test")

and I get this error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object

And when I try convert it to NSData and then try retrieve it, it always comes back as nil.

Here is the code:

var buyData = [Int : String]()
var buyingTotal = [String : [Int: String]]()
var totalBuy = [Int : [String : [Int: String]]]()


let buyerDict = defaults.dictionary(forKey: "buyerDict")
let test = defaults.dictionary(forKey: "test")
func userDefaultSave(){

    buyData[0] = value
    buyData[1] = value
    buyData[2] = value
    buyData[3] = value
    
    buyingTotal["skuu"] = buyData
    totalBuy[0] = buyingTotal
    
    let data: Data = NSKeyedArchiver.archivedData(withRootObject: totalBuy) /// converts to NS Data
    defaults.set(data, forKey: "buyerDict")

    defaults.set(totalBuy, forKey: "test")
    if let dic = defaults.dictionary(forKey: "test") as? [Int : [String : [Int: String]]]  {
        print(dic)
    }

    let retrieved = defaults.object(forKey: "buyerDict") as! Data
    let dictionary: Dictionary? = NSKeyedUnarchiver.unarchiveObject(with: retrieved) as? [String : Any]
    
    print("dictionary--->", dictionary as Any)
}

Can anyone help me?


Solution

  • your dictionary need to change key Int to String Or convert dictionary to Data and retrieve it.

    try this method to set and get your value from userdefault

    let USERDEFAULT = UserDefaults.standard
    
    class func setUserValueArchiver(value:Any, key :String) -> Void{
        guard !(value is NSNull) else {
            return
        }
        do{
            let archive = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
            USERDEFAULT.set(archive, forKey: key)
            USERDEFAULT.synchronize()
        }catch let error{
            Log("Error Save in UserDefault \(error.localizedDescription)")
        }
    }
    
    class func getUserUnArchiveData(key : String) -> Any?{
        if let userdata = USERDEFAULT.object(forKey: key) as? Data{
            do{
                let unarchived = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(userdata)
                return unarchived
            }catch let error{
                Log("Error At Get UserDATA :\(error.localizedDescription)")
            }
        }
        return nil
    }