Robert Robert - 26 days ago 8
Swift Question

How can I encode (with NSCoding) an enum that has no rawValue?

I'm trying to make my class conform to

NSCoding
, but running into problems because one of its properties is an enum, like this:

enum Direction {
case north
case south
}


If enums were codable I could do it like this:

class MyClass: NSObject, NSCoding {
var direction: Direction!
required init(coder aDecoder: NSCoder) {
direction = aDecoder.decodeObject(forKey: "direction") as! Direction
}
func encode(with aCoder: NSCoder) {
aCoder.encode(direction, forKey: "direction")
}
}


but enums aren't codable so
encode()
throws an error.

The answers to "How do I encode enum using NSCoder in swift?" suggest encoding the enum's
rawValue
and then initializing it from
rawValue
on the other end. But in this case,
Direction
doesn't have a
rawValue
!

It does have a
hashValue
, which seems promising. I can encode its
hashValue
without a problem, and decode back to an
Int
on the other end. But there doesn't seem to be a way to initialize an enum from its
hashValue
, so I can't turn it back into a
Direction
.

How can I encode and decode a valueless enum?

Answer Source

I think adding a raw value to the enum here is the solution with the least code and is the most maintainable. So if you can modify the enum, add a raw value.

Now let's assume you can't modify the enum. You still can do this in a few ways.

The first one, which I think is quite ugly, is to add an extension of the enum and add a static method like this:

static func direction(from rawValue: String) -> Direction {
    switch rawValue {
        case: "north": return .north
        case: "south": return .south
        default: fatalError()
    }
}

To convert Direction to a codeable value, use String(describing:) to convert the enum to a string. To convert a string back to an enum, just use the method above.

The second one, slightly better, but still not as good as just adding a raw value.

You use a dictionary:

let enumValueDict: [String, Direction] = [
    "north": .north, "south": .south
]

To convert Direction to a codeable value, use String(describing:) to convert the enum to a string. To convert a string back to an enum, just access the dictionary.