Typo
Type safe UserDefaults wrapper
Usage
Define your namespaces
import Typo
enum Global: NamespaceTag {}
enum Nested: NamespaceTag {}
Define properties (and nested namespaces)
extension Namespace where Tag == Global {
var nestedNS: Namespace<Nested> { .init() }
var intProperty: Property<Int> { .init(default: .zero) }
}
extension Namespace where Tag == Nested {
var stringProperty: Property<String> { .init(default: "") }
}
Create StorageProxy
let proxy = StorageProxy(
namespaceTag: Global.self,
storage: UserDefaults.standard
)
Use the proxy to access your properties
let int = proxy.intProperty
let string = proxy.nestedNS.stringProperty
Using custom types
To store your types, implement Value protocol
public protocol Value: Codable {
static var typeIdentifier: String { get }
}
typeIdentifier
is used to preserve type information when encoding values
Customization
You can customize keys using StorageProxy
initializer
StorageProxy(
namespaceTag: ,
storage: ,
keyPrefix: ,
keyTransformation:
)
Included, but not limited to UserDefauls
If you want Typo to use other types of storages, just implement Storage protocol
public protocol Storage: AnyObject {
subscript(_ key: String) -> Data? { get set }
}
This way you can make any type of key-value storage to be compatible with typo (plain dictionary, NSCache, KeyChain, CoreData, etc)
Migrations
Your app data and it's structure may (and will) evolve over time. Typo provides mechanism to add migrations to properties
extension Namespace where Tag == Global {
var intProperty: Property<Int> {
Property(default: 0)
.migration(
Migration(initialType: Double.self)
.migrate {
Int(exactly: $0) ?? 0
}
)
}
}
Getting keys
In case you need to get keys for your properties (e.g. your storage has some kind of observing), you can call the StorageProxy to get KeyKeeper object and use it the same way you use proxy to get keys for the properties insted of values
let proxy = StorageProxy(
namespaceTag: Global.self,
storage: UserDefaults.standard
)
print(proxy().nestedNS.stringProperty) // "nestedNS/stringProperty"
Contribute
Feel free to open an issue or pull-request