-
Notifications
You must be signed in to change notification settings - Fork 0
Usage
@EFStorageUserDefaults(forKey: "someKey")
var someValueToBeStoredInUserDefaults: String = "Default Value"
let someReference: EFStorageUserDefaultsRef<String> = UserDefaults.efStorage.someKey
this is equivalent to
let someReference = EFStorageUserDefaultsRef<String>.forKey("someKey")
and you can access the value stored in UserDefaults.standard
by
someReference.content
which can be simplified as
UserDefaults.efStorage.someKey as String?
and assign the content through
UserDefaults.efStorage.someKey = "OwO"
Should you need to use a different instance, you can do that too
@EFStorageUserDefaults(forKey: "anotherKey",
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:
extension UserDefaults {
private static let appGroup = UserDefaults(
suiteName: "you.user.defaults.group"
)
@_dynamicReplacement(for: makeDefault())
class func makeDefaultForAppGroup() -> Self {
return (UserDefaults.appGroup as? Self) ?? makeDefault()
}
}
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.
@EFStorageComposition(
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
@EFStorageComposition(
EFStorageUserDefaults<String>(wrappedValue: "Nah",
forKey: "sameKey"),
EFStorageMigrate(
from: EFStorageUserDefaults<Int>(
wrappedValue: 1551,
forKey: "sameKey",
persistDefaultContent: true),
by: { number in String(number) }
)
)
var mixedType: String
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:
public protocol KeychainAccessStorable {
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
public enum AsIsKeychainAccessStorable {
case string(String)
case data(Data)
}
public protocol UserDefaultsStorable {
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.
public protocol AsIsUserDefaultsStorable: UserDefaultsStorable { }
public protocol YYCacheStorable {
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.
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.