在NSUserDefaults(Swift)中存储具有关联值的枚举

时间:2016-08-29 07:39:59

标签: swift enums swift2.3

我希望将带有相关值的枚举传递给Today Extension,因为我使用的是NSUserDefaults,因为Enum不符合AnyObject,似乎没有直接的方法。

enum DeepLinkAction {
  case StartPractice(lessonName:String)
  case StartTest
  case Letters(didComplete:Bool, iconURL:String)
}

我尝试使用NSKeyedArchiver,但需要符合AnyObject。

有没有办法做到这一点,或者我应该删除相关的值?

谢谢

2 个答案:

答案 0 :(得分:4)

编写自己的存档

这将枚举与关联值转换为属性列表表示(字典),可以直接保存在用户默认值中,并可以转换回枚举类型。

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)

答案 1 :(得分:0)

正如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)
    }
  }
}
上面示例代码中的

DownloadStateRoute必须是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)
}