在 NSUserDefaults 中存储具有关联值的枚举 (Swift)
Store Enum with associated values in NSUserDefaults (Swift)
我希望将具有关联值的枚举传递给 Today Extension,因为我为此使用 NSUserDefaults,似乎没有直接的方法可以做到这一点,因为 Enum 不符合 AnyObject。
enum DeepLinkAction {
case StartPractice(lessonName:String)
case StartTest
case Letters(didComplete:Bool, iconURL:String)
}
我尝试使用 NSKeyedArchiver
但需要符合 AnyObject。
有没有办法做到这一点,或者我应该删除关联值?
谢谢
编写您自己的 archiver。
这会将具有关联值的枚举转换为 属性 列表表示形式(字典),它可以直接保存在用户默认值中,并且可以转换回枚举类型。
enum DeepLinkAction {
case StartPractice(lessonName:String)
case StartTest
case Letters(didComplete:Bool, iconURL:String)
var propertyListRepresentation : [String:AnyObject] {
switch self {
case .StartPractice(let lessonName) : return ["StartPractice" : lessonName]
case .StartTest : return ["StartTest" : ""]
case .Letters(let complete, let iconURL) : return ["Letters" : [complete, iconURL]]
}
}
init(propertyList: [String:AnyObject]) {
assert(!propertyList.isEmpty, "property list must contain one key")
let key = propertyList.keys.first!
let value = propertyList[key]!
switch key {
case "StartPractice": self = .StartPractice(lessonName: value as! String)
case "Letters":
let parameters = value as! [AnyObject]
self = .Letters(didComplete: parameters[0] as! Bool, iconURL: parameters[1] as! String)
default: self = .StartTest
}
}
}
let action = DeepLinkAction.Letters(didComplete: false, iconURL: "http://myServer.com/path")
let plist = action.propertyListRepresentation // ["Letters": [0, "http://myServer.com/path"]]
let action2 = DeepLinkAction(propertyList: plist)
正如 here 所描述的那样,在 Swift4 中,您现在可以使用 Codable
协议将枚举与关联值存储在 NSUserDefaults
中。你可以使用类似下面的东西
enum Example {
case caseOne(a: DownloadState, b: Route)
case caseTwo(a: String, b: Int, c: Data?)
}
extension Example: Codable {
private enum CodingKeys: String, CodingKey {
case base, caseOneParams, caseTwoParams
}
private enum Base: String, Codable {
case caseOne, caseTwo
}
private struct CaseOneParams: Codable {
let a: DownloadState
let b: Route
}
private struct CaseTwoParams: Codable {
let a: String
let b: Int
let c: Data?
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .caseOne(let a, let b):
try container.encode(Base.caseOne, forKey: .base)
try container.encode(CaseOneParams(a: a, b: b), forKey: .caseOneParams)
case .caseTwo(let a, let b, let c):
try container.encode(Base.caseTwo, forKey: .base)
try container.encode(CaseTwoParams(a: a, b: b, c: c), forKey: .caseTwoParams)
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let base = try container.decode(Base.self, forKey: .base)
switch base {
case .caseOne:
let caseOneParams = try container.decode(CaseOneParams.self, forKey: .caseOneParams)
self = .caseOne(a: caseOneParams.a, b: caseOneParams.b)
case .caseTwo:
let caseTwoParams = try container.decode(CaseTwoParams.self, forKey: .caseTwoParams)
self = .caseTwo(a: caseTwoParams.a, b: caseTwoParams.b, c: caseTwoParams.c)
}
}
}
上面示例代码中的 DownloadState
和 Route
必须是 Codable
类型。
然后写入NSUserDefaults
let example: Example = ...
UserDefaults.standard.set(try? PropertyListEncoder().encode(example), forKey: "yourExampleKey")
阅读
if let data = UserDefaults.standard.value(forKey:"yourExampleKey") as? Data {
let example = try? PropertyListDecoder().decode(Example.self, from: data)
}
我希望将具有关联值的枚举传递给 Today Extension,因为我为此使用 NSUserDefaults,似乎没有直接的方法可以做到这一点,因为 Enum 不符合 AnyObject。
enum DeepLinkAction {
case StartPractice(lessonName:String)
case StartTest
case Letters(didComplete:Bool, iconURL:String)
}
我尝试使用 NSKeyedArchiver
但需要符合 AnyObject。
有没有办法做到这一点,或者我应该删除关联值?
谢谢
编写您自己的 archiver。
这会将具有关联值的枚举转换为 属性 列表表示形式(字典),它可以直接保存在用户默认值中,并且可以转换回枚举类型。
enum DeepLinkAction {
case StartPractice(lessonName:String)
case StartTest
case Letters(didComplete:Bool, iconURL:String)
var propertyListRepresentation : [String:AnyObject] {
switch self {
case .StartPractice(let lessonName) : return ["StartPractice" : lessonName]
case .StartTest : return ["StartTest" : ""]
case .Letters(let complete, let iconURL) : return ["Letters" : [complete, iconURL]]
}
}
init(propertyList: [String:AnyObject]) {
assert(!propertyList.isEmpty, "property list must contain one key")
let key = propertyList.keys.first!
let value = propertyList[key]!
switch key {
case "StartPractice": self = .StartPractice(lessonName: value as! String)
case "Letters":
let parameters = value as! [AnyObject]
self = .Letters(didComplete: parameters[0] as! Bool, iconURL: parameters[1] as! String)
default: self = .StartTest
}
}
}
let action = DeepLinkAction.Letters(didComplete: false, iconURL: "http://myServer.com/path")
let plist = action.propertyListRepresentation // ["Letters": [0, "http://myServer.com/path"]]
let action2 = DeepLinkAction(propertyList: plist)
正如 here 所描述的那样,在 Swift4 中,您现在可以使用 Codable
协议将枚举与关联值存储在 NSUserDefaults
中。你可以使用类似下面的东西
enum Example {
case caseOne(a: DownloadState, b: Route)
case caseTwo(a: String, b: Int, c: Data?)
}
extension Example: Codable {
private enum CodingKeys: String, CodingKey {
case base, caseOneParams, caseTwoParams
}
private enum Base: String, Codable {
case caseOne, caseTwo
}
private struct CaseOneParams: Codable {
let a: DownloadState
let b: Route
}
private struct CaseTwoParams: Codable {
let a: String
let b: Int
let c: Data?
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
switch self {
case .caseOne(let a, let b):
try container.encode(Base.caseOne, forKey: .base)
try container.encode(CaseOneParams(a: a, b: b), forKey: .caseOneParams)
case .caseTwo(let a, let b, let c):
try container.encode(Base.caseTwo, forKey: .base)
try container.encode(CaseTwoParams(a: a, b: b, c: c), forKey: .caseTwoParams)
}
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let base = try container.decode(Base.self, forKey: .base)
switch base {
case .caseOne:
let caseOneParams = try container.decode(CaseOneParams.self, forKey: .caseOneParams)
self = .caseOne(a: caseOneParams.a, b: caseOneParams.b)
case .caseTwo:
let caseTwoParams = try container.decode(CaseTwoParams.self, forKey: .caseTwoParams)
self = .caseTwo(a: caseTwoParams.a, b: caseTwoParams.b, c: caseTwoParams.c)
}
}
}
上面示例代码中的 DownloadState
和 Route
必须是 Codable
类型。
然后写入NSUserDefaults
let example: Example = ...
UserDefaults.standard.set(try? PropertyListEncoder().encode(example), forKey: "yourExampleKey")
阅读
if let data = UserDefaults.standard.value(forKey:"yourExampleKey") as? Data {
let example = try? PropertyListDecoder().decode(Example.self, from: data)
}