Storage
Store values using unique, randomly generated identifiers.
This packages consists of three types: A Storage
class, a UniqueIdentifiable
protocol, and a UniqueID
struct.
You use Storage
's auto-getting and setting methods to manipulate the values of computed properties without the need for extra, often unnecessary code.
Create a type, and declare conformance to the UniqueIdentifiable
protocol. The only requirement is that you implement an id
property of the UniqueID
type.
struct MyType: UniqueIdentifiable {
let id = UniqueID()
}
On its own, this has very few practical applications, but when combined with the Storage
type, the list of applications grows. Storage
's usefulness becomes apparent when dealing with protocol extensions. You can use the id
property to get and set computed properties, something that otherwise would be very difficult to achieve, as extensions in Swift cannot contain stored properties.
fileprivate var storage = Storage()
protocol Rock: UniqueIdentifiable { }
extension Rock {
var type: String? {
get { storage.autoGet(id) }
set { storage.autoSet(newValue, id) }
}
var color: String? {
get { storage.autoGet(id) }
set { storage.autoSet(newValue, id) }
}
var texture: String? {
get { storage.autoGet(id) }
set { storage.autoSet(newValue, id) }
}
}
The properties above automatically get stored under new ids that are created by combining the id of the enclosing Rock
instance with an id that is synthesized from the name of the property.
You can also provide a backup value in the event that the property has not been set. This lets you avoid having to mark the properties as optional, and provide a default state for every instance of a type. Let's change the property declarations we defined above and give them default values.
var type: String {
get { storage.autoGet(id, backup: "pumice") }
set { storage.autoSet(newValue, id) }
}
var color: String {
get { storage.autoGet(id, backup: "gray") }
set { storage.autoSet(newValue, id) }
}
var texture: String {
get { storage.autoGet(id, backup: "rough") }
set { storage.autoSet(newValue, id) }
}
You can also store static properties, using your type's typeID
static identifier. Let's extend Rock
one more time and add some characteristics that every rock has.
// Note: You probably wouldn't want to make these specific properties settable,
// as it's very difficult to change a rock, but I'm running out of ideas.
extension Rock {
static var biggerThanABreadbox: Bool {
get { storage.autoGet(typeID, backup: .random()) }
set { storage.autoSet(newValue, typeID) }
}
static var animalVegetableOrMineral: String {
get { storage.autoGet(typeID, backup: "mineral") }
set { storage.autoSet(newValue, typeID) }
}
}