-
Notifications
You must be signed in to change notification settings - Fork 0
Usage
As @propertyWrapper
var someValueToBeStoredInUserDefaults: String = "Default Value"
Through @dynamicMemberLookup
this is equivalent to
and you can access the value stored in UserDefaults.standard by
which can be simplified as
and assign the content through
Non-default Container
Should you need to use a different instance, you can do that too
in: UserDefaults.standard,
persistDefaultContent: true)
var inAnotherStorage: Bool = true
UserDefaults.standard.efStorage.anotherKey // either content or the reference to it
EFStorageUserDefaultsRef<Bool>.forKey("anotherKey", in: UserDefaults.standard)
Or, if you want to replace the default container for all, try this:
private static let appGroup = UserDefaults(
suiteName: "you.user.defaults.group"
)
@_dynamicReplacement(for: makeDefault())
class func makeDefaultForAppGroup() -> Self {
return (UserDefaults.appGroup as? Self) ?? makeDefault()
}
}
Supported Containers
As of now, we offer support for UserDefaults and Keychain (provided by KeychainAccess).
You can combine them to form a new type of container, or to support previous keys.
EFStorageUserDefaults(wrappedValue: false, forKey: "isNewUser"),
EFStorageKeychainAccess(wrappedValue: false, forKey: "isNewUser"))
var isNewUser: Bool
@SomeEFStorage(
EFStorageKeychainAccess(wrappedValue: false, forKey: "paidBefore")
+ EFStorageUserDefaults(wrappedValue: false, forKey: "paidBefore")
+ EFStorageUserDefaults(wrappedValue: true,
forKey: "oldHasPaidBeforeKey",
persistDefaultContent: true))
var hasPaidBefore: Bool
To migrate from another data type, you can use a migrator
EFStorageUserDefaults<String>(wrappedValue: "Nah",
forKey: "sameKey"),
EFStorageMigrate(
from: EFStorageUserDefaults<Int>(
wrappedValue: 1551,
forKey: "sameKey",
persistDefaultContent: true),
by: { number in String(number) }
)
)
var mixedType: String
More Storables
While EFStorage provides extension on common types you may want to store, there are times when you need to make some other types storable. You can look at the source code of EFStorage to see how we did it, and these are the protocols you may want to adopt:
KeychainAccess
func asKeychainAccessStorable() -> Result<AsIsKeychainAccessStorable, Error>
static func fromKeychain(_ keychain: Keychain, forKey key: String) -> Self?
}
Since KeychainAccess only supports String or Data, you have to convert it to one of those
case string(String)
case data(Data)
}
UserDefaults
func asUserDefaultsStorable() -> Result<AsIsUserDefaultsStorable, Error>
static func fromUserDefaults(_ userDefaults: UserDefaults, forKey key: String) -> Self?
}
UserDefaults is interesting, because it takes Any. Every type that you might
expect to save in UserDefaults directly has adopted the AsIsUserDefaultsStorable protocol,
so don't conform to it unless you know what you are doing.
YYCache
func asYYCacheStorable() -> Result<NSCoding, Error>
static func fromYYCache(_ yyCache: YYCache, forKey key: String) -> Self?
}
YYCache only takes types conforming to NSCoding, so that's easy.
Assertion Failures
EFStorage traps through assertionFailure when types fail to convert to some storable,
which means it only crashes for DEBUG and not for production (it just don't do anything).
You can swizzle onConversionFailure/onStorageFailure methods using @_dynamicReplacement(for:)
to provide your own, custom logic around error handling.