如何将符合Codable协议的枚举保存到UserDefaults?

Adr*_*ian 5 nsuserdefaults swift codable

跟进我之前的问题

我设法使我的枚举符合 Codable 协议,实现了 init() 和encode(),它似乎可以工作。

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

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

enum LoggedOutState: String {
    case Unregistered
    case Registered
}

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

    enum CodingError: Error {
        case decoding(String)

    }

    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)!)
        }
        else if let loggedOut = try? values.decode(String.self, forKey: .loggedOut) {
            self = .LoggedOut(LoggedOutState(rawValue: loggedOut)!)
        }
        else {
            throw CodingError.decoding("Decoding failed")
        }
    }

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

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



class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let state = UserState.LoggedIn(.playing)
        UserDefaults.standard.set(state, forKey: "state")
    }
}
Run Code Online (Sandbox Code Playgroud)

我的问题是我不知道如何将其保存到 UserDefaults。如果我像现在一样保存它,我在运行应用程序时会收到以下错误:

[User Defaults] Attempt to set a non-property-list object Codable.UserState.LoggedIn(Codable.LoggedInState.playing) as an NSUserDefaults/CFPreferences value for key state
2018-01-20 19:06:26.909349+0200 Codable[6291:789687]
Run Code Online (Sandbox Code Playgroud)

djr*_*ero 4

来自UserDefaults参考:

\n\n
\n

默认对象必须是属性列表\xe2\x80\x94,即NSData、 NSString、\n NSNumber、NSDate、NSArray 或 NSDictionary的实例(或\n 对于集合,是实例的组合) 。如果要存储任何其他类型的对象,通常应该将其存档以创建 NSData 实例。

\n
\n\n

因此,您应该state手动编码并将其存储为数据:

\n\n
if let encoded = try? JSONEncoder().encode(state) {\n    UserDefaults.standard.set(encoded, forKey: "state")\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,读回它:

\n\n
guard let data = UserDefaults.standard.data(forKey: "state") else { fatalError() }\nif let saved = try? JSONDecoder().decode(UserState.self, from: data) {\n    ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n