swift - 如何将符合 Codable 协议(protocol)的枚举保存到 UserDefaults?

标签 swift nsuserdefaults codable

跟进我之前的question :

我设法使我的枚举符合 Codable 协议(protocol),实现了 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")
    }
}

我的问题是我不知道如何将它保存到 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]

最佳答案

来自 UserDefaults 引用:

A default object must be a property list—that is, an instance of (or for collections, a combination of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.

所以你应该手动编码state并将其存储为数据:

if let encoded = try? JSONEncoder().encode(state) {
    UserDefaults.standard.set(encoded, forKey: "state")
}

然后,读回:

guard let data = UserDefaults.standard.data(forKey: "state") else { fatalError() }
if let saved = try? JSONDecoder().decode(UserState.self, from: data) {
    ...
}

关于swift - 如何将符合 Codable 协议(protocol)的枚举保存到 UserDefaults?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48358860/

相关文章:

ios - 如何在 Swift 中将变量值设置回之前的状态?

objective-c - 在自定义 slider 中创建更改值的操作

json - 如何使用 Codable 在 Swift 4 中解析复杂的 JSON

ios - 在原生平台上验证 jwt

swift - 有没有一种简单的方法可以测试您是否匹配一组枚举中的一个?

ios - NSUserDefaults 无法检索图像数组

iphone - NSUserDefault 存在 -iPHONE SDK

ios - 在 iTunes 中不同步的 NSUserDefaults 首选项

json - 使用 Alamofire 快速写入 JSON 中的顶级类型无效

ios - 对于可编码结构,由于 'private' 保护级别,“CodingKeys”无法访问