shannoga shannoga - 3 months ago 21
Swift Question

Store Enum with associated values in NSUserDefaults (Swift)

I wish to pass enums with associated values to a Today Extension, Since I am using NSUserDefaults for that it seems that there is no straight forward way to do that as Enum does not conform to AnyObject.

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


I tried using
NSKeyedArchiver
but is requires conforming to AnyObject.

Is there a way to do that or I should just remove the associated values ?

Thanks

Answer

Write your own archiver.

This converts the enum with the associated value(s) to a property list representation (a dictionary) which can be saved directly in user defaults and can be converted back to the enum type.

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)