I have been trying to figure out how to save an arrays of dictionaries using Enum types with NSCoding.
I have an enum with Medal types
enum Medal: String {
case Unearned = "NoMedal"
case Gold = "GoldMedal"
case Silver = "SilverMedal"
}
I have an array of dictionaries with the medal types in my GameData.swift class.
var medals: [[String: Medal]] = [
["1": .Unearned, "2": .Unearned, "3": .Unearned]
...
]
Than I have this code in the decoder method
convenience required init?(coder decoder: NSCoder) {
self.init()
medals = decoder.decodeObjectForKey(Key.medals) as? [[String: Medal]] ?? medals
}
and this is the encoder method which I believe is causing me the issues
// MARK: - Encode
func encodeWithCoder(encoder: NSCoder) {
encoder.encodeObject(medals as? AnyObject, forKey: Key.medals)
}
The problem is on a restart it is not saving/loading the medal array, it keeps resetting to default.
I have also tried this
encoder.encodeObject(medals as? [[String: Medal]], forKey: Key.medals)
and it causes a compiler error.
I also cannot use the regular syntax
encoder.encodeObject(medals, forKey: Key.medals)
Like I would for a array of dictionaries using normal values (e.g [String: Int]) as the compiler will also throw an error
medals
is not an AnyObject
, so when you encode it as? AnyObject
you get nil
.
Just because the enum has raw string values doesn't mean you can automatically bridge it to [String:String]
. You have to do that yourself. For example (using Airspeed Velocity's version of mapValues
):
convenience required init?(coder decoder: NSCoder) {
self.init()
if let medalStrings = decoder.decodeObjectForKey(Key.medals) as? [[String: String]] {
medals = medalStrings.map { $0.mapValues { Medal(rawValue: $0) ?? .Unearned } }
}
}
func encodeWithCoder(encoder: NSCoder) {
let medalStrings = medals.map { $0.mapValues { $0.rawValue } }
encoder.encodeObject(medalStrings, forKey: Key.medals)
}