Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save Array of dictionaries with Enum type, NSCoding

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

like image 474
crashoverride777 Avatar asked Feb 06 '26 16:02

crashoverride777


1 Answers

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)
}
like image 59
Rob Napier Avatar answered Feb 09 '26 10:02

Rob Napier



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!