You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Define Compatible protocol that allows value to be plist compatible
The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.
Next, define Defaults that accepts UserDefaults as initialize dependency, so that we can swap UserDefaults.
Key with generic type
We define Key with phantom type Value so we know which value this key is pointing to, this makes it easier to reason about the code.
Since Swift has limitation Static stored properties not supported in generic types, we can't extend our Key with static stored properties, we have to do via computed property
This works, but does not look nice. To workaround this, we define class AnyKey and make our Key class as well and inherited this AnyKey class.
Make a typealias typealias Keys = AnyKey so we can refer to Defaults.Keys when we define our keys.
publicclassDefaults{publicvarsuite:UserDefaultspublicinit(suite:UserDefaults=.standard){self.suite = suite
}public subscript<Value:Compatible>(key:Key<Value>)->Value{get{
if let value = suite.object(forKey: key.name)as?Value{return value
}return key.defaultValue
}set{
suite.set(newValue, forKey: key.name)}}publicfunc exists<Value:Compatible>(key:Key<Value>)->Bool{
suite.object(forKey: key.name)!=nil}}extensionDefaults{publictypealiasKeys=AnyKeypublicclassKey<Value:Compatible>:AnyKey{vardefaultValue:Valuepublicinit(_ name:String, default defaultValue:Value){self.defaultValue = defaultValue
super.init(name: name)}}publicclassAnyKey{varname:Stringinit(name:String){self.name = name
}}}extensionDefaults.AnyKey:Equatable{publicstaticfunc==(lhs:Defaults.AnyKey, rhs:Defaults.AnyKey)->Bool{
lhs.name == rhs.name
}}extensionDefaults.AnyKey:Hashable{publicfunc hash(into hasher:inoutHasher){
hasher.combine(name)}}
How about Optional
We can support Optional as well, as long as it's underlying value is compatible. Since the type is defined via Key, we can't accidentally use Optional when the Key has non Optional value
extensionOptional:Compatiblewhere Wrapped:Compatible{}extensionDefaults{public subscript<Value:Compatible>(key:Key<Optional<Value>>)->Value?{get{
if let value = suite.object(forKey: key.name)as?Value{return value
}returnnil}set{
if let newValue {
suite.set(newValue, forKey: key.name)}else{
suite.removeObject(forKey: key.name)}}}}extensionDefaults.Keys{staticletoptional=Defaults.Key<Int?>("optional.int", default:nil)}func testOptional(){XCTAssertNil(defaults[.optional])defaults[.optional]=1XCTAssertEqual(defaults[.optional],1)defaults[.optional]=nilXCTAssertNil(defaults[.optional])}
The text was updated successfully, but these errors were encountered:
We want to have a swifty UserDefaults API that works with subscript and in a type safe manner.
UserDefaults plist compatibility
Define
Compatible
protocol that allows value to be plist compatibleNext, define
Defaults
that acceptsUserDefaults
as initialize dependency, so that we can swap UserDefaults.Key with generic type
We define
Key
with phantom typeValue
so we know which value this key is pointing to, this makes it easier to reason about the code.Since Swift has limitation
Static stored properties not supported in generic types
, we can't extend ourKey
with static stored properties, we have to do via computed propertyThis works, but does not look nice. To workaround this, we define class
AnyKey
and make ourKey
class as well and inherited thisAnyKey
class.Make a typealias
typealias Keys = AnyKey
so we can refer toDefaults.Keys
when we define our keys.How about Optional
We can support
Optional
as well, as long as it's underlying value is compatible. Since the type is defined viaKey
, we can't accidentally use Optional when the Key has non Optional valueThe text was updated successfully, but these errors were encountered: