Reputation: 3215
I'm building a helper to enable typed access to NSUserDefaults
properties. Something like this:
struct UserDefaults {
private static var standardUserDefaults: NSUserDefaults = {
return NSUserDefaults.standardUserDefaults()
}()
private static let propKey = "PROP"
static var prop: Bool {
get {
return standardUserDefaults.boolForKey(propKey)
}
set {
standardUserDefaults.setBool(newValue, forKey: propKey)
standardUserDefaults.synchronize()
}
}
}
This way I can have a nice syntax for reading and writing to NSUserDefaults
:
UserDefaults.prop // read
UserDefaults.prop = false // write
The problem is that there's a lot of boilerplate code for this, I need 10 lines for each aditional property.
Is there any way of reducing the amount of lines needed for each new property? Reusing getter and setter? Any kind of run time generator?
Upvotes: 1
Views: 884
Reputation: 6211
I like David's answer much better, but here's another option. Drops your 10 lines per variable down to 5 (mainly because of new line removal...)
struct UserDefaults {
private static var standardUserDefaults: NSUserDefaults = {
return NSUserDefaults.standardUserDefaults()
}()
//Repeate these 5 lines for all new variables,
//changing the as? to the proper variable type
//Adding in a default value for the return in
//case the as? cast fails for any reason
private static let propKey = "PROP"
static var prop: Bool {
get { return (getVar(propKey) as? Bool) ?? false }
set { setVar(newValue, key:propKey) }
}
//The generic set/get
private static func getVar(key : String) -> AnyObject?
{
return standardUserDefaults.objectForKey(key)
}
private static func setVar(newValue : AnyObject, key : String)
{
if(newValue is Bool)
{
standardUserDefaults.setBool((newValue as? Bool)!, forKey: key)
}
//... More cases here
else if(newValue == nil)
{
standardUserDefaults.removeObjectForKey(key)
}
else
{
standardUserDefaults.setObject(newValue, forKey: key)
}
standardUserDefaults.synchronize()
}
}
Upvotes: 0
Reputation: 41226
You can try wrapping the actual value in a class that handles all the dirty work for you:
class WrappedUserDefault<T> {
let key : String
let defaultValue : T
var value : T {
get {
if let value = UserDefaults.standardUserDefaults.objectForKey(key) as? T {
return value
} else {
return defaultValue
}
}
set {
if let value = newValue as? AnyObject {
UserDefaults.standardUserDefaults.setValue(value, forKey: key)
} else {
UserDefaults.standardUserDefaults.removeObjectForKey(key)
}
UserDefaults.standardUserDefaults.synchronize()
}
}
init(key:String, defaultValue:T) {
self.key = key
self.defaultValue = defaultValue
}
}
struct UserDefaults {
static let standardUserDefaults = NSUserDefaults.standardUserDefaults()
static let ready = WrappedUserDefault<Bool>(key:"ready", defaultValue: true)
static let count = WrappedUserDefault<Int>(key: "count", defaultValue: 0)
}
Then with just a little bit more code you wind up with:
UserDefaults.count.value++
UserDefaults.ready.value = true
UserDefaults.ready.value
If the verbosity of ready.value
bothers you, you can somewhat hide that, although then you're back to you're back to having a fair amount of copy/paste code:
struct UserDefaults {
static let standardUserDefaults = NSUserDefaults.standardUserDefaults()
private static let readyWrapper = WrappedUserDefault<Bool>(key:"ready", defaultValue: true)
static var ready : Bool {
get { return readyWrapper.value }
set { readyWrapper.value = newValue }
}
}
At least in this case though, the copy/paste code is fairly trivial, so unlikely to need to be altered in the future.
Upvotes: 1