Skip to content

Instantly share code, notes, and snippets.

@dmrev
Last active December 11, 2015 18:28
Show Gist options
  • Save dmrev/cd95b921c6c0c4cae54c to your computer and use it in GitHub Desktop.
Save dmrev/cd95b921c6c0c4cae54c to your computer and use it in GitHub Desktop.
Another statically-typed NSUserDefaults inspired by https://github.com/radex/SwiftyUserDefaults
class SmartKeyBase: Equatable, Hashable {
private let defaults = NSUserDefaults.standardUserDefaults()
private(set) static var allKeys = Set<SmartKeyBase>()
let name: String
static func removeAllValues() {
allKeys.forEach { $0.removeValue() }
}
init(_ name: String) {
self.name = name
assert(!SmartKeyBase.allKeys.contains(self), "Duplicate SmartKey key found: \(name).")
SmartKeyBase.allKeys.insert(self)
}
func hasValue() -> Bool {
return defaults.objectForKey(name) != nil
}
func removeValue() {
defaults.removeObjectForKey(name)
}
var hashValue: Int {
return name.hashValue
}
}
func ==(left: SmartKeyBase, right: SmartKeyBase) -> Bool {
return left.name == right.name
}
class SmartKey<T>: SmartKeyBase {
let defaultValue: T
// `value` - default value for this key
init(_ name: String, _ value: T) {
self.defaultValue = value
super.init(name)
}
var value: T {
get {
if let value = defaults.objectForKey(name) {
switch value {
case let data as NSData: return NSKeyedUnarchiver.unarchiveObjectWithData(data) as! T
default:
if let value = value as? T {
return value
}
else {
removeValue()
// warning user?
return defaultValue
}
}
}
else {
return defaultValue
}
}
set {
switch newValue {
case let value as Int: defaults.setInteger(value, forKey: name)
case let value as Double: defaults.setDouble(value, forKey: name)
case let value as Bool: defaults.setBool(value, forKey: name)
case let value as String: defaults.setObject(value, forKey: name)
case let value as NSDate: defaults.setObject(value, forKey: name)
//case let value as NSData: defaults.setObject(value, forKey: name)
case let value as NSObject where value is NSCoding: defaults.setObject(NSKeyedArchiver.archivedDataWithRootObject(value), forKey: name)
default: assertionFailure("Unsupported `value` type: \(newValue.dynamicType).")
}
}
}
var optionalValue: T? {
return hasValue() ? value : nil
}
}
extension SmartKey: CustomStringConvertible {
var description: String {
return "\(name): \(optionalValue), \(defaultValue)"
}
}
struct UserDefaults {
static let currentMap = SmartKey<String>("currentMap", "moscow")
static let count = SmartKey<Int>("count", 0)
static let color = SmartKey<UIColor>("color", .whiteColor())
static let ints = SmartKey<[Int]>("ints", [1, 2])
static let recentRoutes = SmartKey<[SavedRoute]>("recentRoutes", []) // @objc(SavedRoute)
// class SavedRoute: NSObject, NSCoding { ... }
static let date = SmartKey<NSDate>("date", NSDate.distantPast())
static let dict = SmartKey<[String: SavedRoute]>("dict", ["first": SavedRoute()])
static let url = SmartKey<NSURL>("url", NSURL(string: "http://localhost")!)
}
UserDefaults.count.value++
UserDefaults.ints.value += [3]
// ...etc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment