Adrian
Adrian

Reputation: 20058

How to use Codable protocol for an enum with other enum as associated value (nested enum)

I asked a question yesterday on how to save a nested enum inside UserDefaults.
I am trying to use the Codable protocol for this, but not sure if I am doing it correctly.

Here is again the enum I want to store -> UserState:

enum UserState {
    case LoggedIn(LoggedInState)
    case LoggedOut(LoggedOutState)
}

enum LoggedInState: String {
    case playing
    case paused
    case stopped
}

enum LoggedOutState: String {
    case Unregistered
    case Registered
}

Here are the steps I did so far:

Conform to Codable protocol and specify which are the keys we use for encode/decode:

extension UserState: Codable {
    enum CodingKeys: String, CodingKey {
        case loggedIn
        case loggedOut
    }

    enum CodingError: Error {
        case decoding(String)       
    }
}

Added initializer for decode:

init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    if let loggedIn = try? values.decode(String.self, forKey: .loggedIn) {
        self = .LoggedIn(LoggedInState(rawValue: loggedIn)!)
    }

    if let loggedOut = try? values.decode(String.self, forKey: .loggedOut) {
        self = .LoggedOut(LoggedOutState(rawValue: loggedOut)!)
    }

    throw CodingError.decoding("Decoding failed")
}

Added encode method:

func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)

    switch self {
    case let .LoggedIn(value):
        try container.encode(value, forKey: .loggedIn) // --> Ambiguous reference to member 'encode(_:forKey:)'
    case let .LoggedOut(value):
        try container.encode(value, forKey: .loggedOut) // --> Ambiguous reference to member 'encode(_:forKey:)'
    }
}

The encode method gives me the above two errors. Not sure right now what I am doing wrong or if I am on the right track.

Any idea what I am doing wrong and what causes these two ambiguous errors ?

Upvotes: 1

Views: 1325

Answers (1)

vadian
vadian

Reputation: 285069

The associated value is LoggedInState or LoggedOutState but you have to encode its rawValue (String):

    case let .LoggedIn(value):
        try container.encode(value.rawValue, forKey: .loggedIn)
    case let .LoggedOut(value):
        try container.encode(value.rawValue, forKey: .loggedOut)
    }

according to the decode method where you're creating the enum cases from the rawValue.

Upvotes: 1

Related Questions