Search code examples
swiftuserdefaults

Error on Saving Nested Map ([String: Any]) in UserDefaults


I'm trying to save a nested Map in Swift, and it's not working as expected. The Map structure looks something like this:

[
    "racesMap": [
        32904: "Races(bestTime: 1, bonusRanking: 0, countryID: 0, ...)",
        32905: "Races(bestTime: 1, bonusRanking: 0, countryID: 0, ...)",

    ],
    "userName": "Alpha",
]
 let inputMap: [String: Any] = above map
 defaults.set(inputMap, forKey: "keyFormapSaving")

Saving username works, but encountering an error when attempting to save the "racesMap" key. Seeking assistance to identify and resolve the issue.

Error by XCODE:

Thread 1: "Attempt to insert non-property list object {\n
32904 = "app.Races(bestTime: 1, bonusRanking: 0, countryID: 0)";\n} for key keyFormapSaving"


Solution

  • Thanks @Joakim Danielson I've achived it by just converting the model class to Data object and reverse it for getting

    splitting my map to save like below:

    func saveUserRaceData(inputMap: [String: Any]) {
        do {
            var mInputMap = inputMap
            saveRacesMapToUserDefaults(racesMap: mInputMap["racesMap"] as! [String : Races])
            mInputMap.removeValue(forKey: "racesMap")
            defaults.set(mInputMap, forKey: "toud")
        } catch {
            print("Error: \(error)")
        }
    }
    
    func saveRacesMapToUserDefaults(racesMap: [String: Races]) {
        var racesData: [String: Data] = [:]
        for (key, racesObject) in racesMap {
            do {
                let racesObjectData = try JSONEncoder().encode(racesObject)
                racesData[key] = racesObjectData
            } catch {
                print("Error encoding Races object for key \(key): \(error)")
            }
        }
        defaults.set(racesData, forKey: "racesMapKey")
    }
    

    To load/get data from default as one map:

     func loadRacesMapFromUserDefaults() ->  [String: Races] {
        var racesMap: [String: Races] = [:]
    
        // Retrieve Data from UserDefaults
        if let racesData = defaults.dictionary(forKey: "racesMapKey") as? [String: Data] {
            // Convert Data back to Races objects
            racesMap = racesData.reduce(into: [:]) { (result, pair) in
                do {
                    let racesObject = try JSONDecoder().decode(Races.self, from: pair.value)
                    result[pair.key] = racesObject
                } catch {
                    print("Error decoding Races object for key \(pair.key): \(error)")
                }
            }
        }
        return racesMap
    }
    
    func getUserRaceData() -> [String: Any] {
        var outputMap: [String: Any] = [:]
        if let jsonString = defaults.dictionary(forKey: "toud") as? [String: Any] {
            for (key, value) in jsonString {
                outputMap[key] = value
            }
            outputMap["racesMap"] = loadRacesMapFromUserDefaults()
        }
        return outputMap
    }