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”

  • 1

    “…encountering an error”, what error is that? Please include it in the question.

    – 

  • @JoakimDanielson I’ve added that could you please look into it?

    – 

  • 1

    Convert the map to a custom type (struct) that conforms to Codable and convert it into Data before saving it to UserDefaults.

    – 

  • could you please write it as it’s difficult to get that!!!

    – 

  • Another option is to modify the map so it can be stored as a property list object by changing the keys for “racesMap” to strings, "32904": "Races(.... Then you can use the code you have as is.

    – 




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
}

Leave a Comment