How can I store a Swift enum value in NSUserDefaults
Using Codable
protocol
Extent Environment
enum that conforms to Codable
protocol to encode and decode values as Data
.
enum Environment: String, Codable {
case Production
case Staging
case Dev
}
A wrapper for UserDefaults
:
struct UserDefaultsManager {
static var userDefaults: UserDefaults = .standard
static func set<T>(_ value: T, forKey: String) where T: Encodable {
if let encoded = try? JSONEncoder().encode(value) {
userDefaults.set(encoded, forKey: forKey)
}
}
static func get<T>(forKey: String) -> T? where T: Decodable {
guard let data = userDefaults.value(forKey: forKey) as? Data,
let decodedData = try? JSONDecoder().decode(T.self, from: data)
else { return nil }
return decodedData
}
}
Usage
// Set
let environment: Environment = .Production
UserDefaultsManager.set(environment, forKey: "environment")
// Get
let environment: Environment? = UserDefaultsManager.get(forKey: "environment")
Here is another alternative that can be be easily used with enums based on types (like String, Int etc) that can be stored by NSUserDefaults.
@propertyWrapper
struct StoredProperty<T: RawRepresentable> {
let key: String
let defaultValue: T
init(_ key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T {
get {
guard let rawValue = UserDefaults.standard.object(forKey: key) as? T.RawValue, let value = T(rawValue: rawValue) else {
return defaultValue
}
return value
}
set {
UserDefaults.standard.set(newValue.rawValue, forKey: key)
}
}
}
Example usage:
enum Environment: String {
case Production
case Staging
case Dev
}
@StoredProperty("Environment", defaultValue: .Dev)
var storedProperty: Environment
If you would like to save/read data from UserDefaults and separate some logic, you can do it in following way (Swift 3):
enum Environment: String {
case Production
case Staging
case Dev
}
class UserDefaultsManager {
static let shared = UserDefaultsManager()
var environment: Environment? {
get {
guard let environment = UserDefaults.standard.value(forKey: kSavedEnvironmentDefaultsKey) as? String else {
return nil
}
return Environment(rawValue: environment)
}
set(environment) {
UserDefaults.standard.set(environment?.rawValue, forKey: kSavedEnvironmentDefaultsKey)
}
}
}
So saving data in UserDefaults will look this way:
UserDefaultsManager.shared.environment = Environment.Production
And reading data, saved in UserDefaults in this way:
if let environment = UserDefaultsManager.shared.environment {
//you can do some magic with this variable
} else {
print("environment data not saved in UserDefaults")
}
Using rawValue for the enum is one way of using types that can be stored in NSUserDefaults, define your enum to use a rawValue. Raw values can be strings, characters, or any of the integer or floating-point number types :
enum Environment: String {
case Production = "Prod"
case Staging = "Stg"
case Dev = "Dev"
}
You can also create an enum instance directly using the rawValue (which could come from NSUserDefaults) like:
let env = Environment(rawValue: "Dev")
You can extract the rawValue (String) from the enum object like this and then store it in NSUserDefaults if needed:
if let myEnv = env {
println(myEnv.rawValue)
}
func saveEnvironment(environment : Environment){
NSUserDefaults.standardUserDefaults().setObject(environment.rawValue, forKey: kSavedEnvironmentDefaultsKey)
}