Introduction
Key-value storage where value object will be automatically released when key object is deallocated.
How to install
The recommended way is to install using CocoaPods:
pod 'XCEAssociatedStorage', '~> 1.0'
How it works
This storage for any given object of Key
type (keyObject
) allows to create and store one and only one instance of Value
object type (valueObject
). Each valueObject
is lazy-initialized on first access and then being stored in the storage till the end of corresponding keyObject
life cycle. This special technique guarantees that the valueObject
will be available while its keyObject
is in memory, but, at the same time, will be released from memory as soon as its keyObject
released, preventing memory leaks, but providing great convenience of dynamically extending any type storage capabiolities on demand.
How to use
It’s recommended to maintain independent instance of AssociatedStorage
type for each Value
type, so the same Key
object can be associated with objects of different Value
types without collisions, unless that’s intendent behaviour when every next association operation may override earlier association with value object of another Value
type.
SimplyInitializable
In case Value
type conforms to SimplyInitializable
protocol, use storage as follows:
let associatedStorage = AssociatedStorage()
class Owner
{
// ...
}
class Dependent: SimplyInitializable
{
init()
{
// ...
}
}
let owner: Owner = // object that is being held in memory elsewhere
let dependentForTheOwner: Dependent = associatedStorage.get(for: owner)
// later:
let dependentAgain: Dependent = associatedStorage.get(for: owner)
// `dependentForTheOwner` is absolutely the same object as `dependentAgain`
KeyObjectInitializable
In case Value
type conforms to KeyObjectInitializable
protocol, use storage as follows:
let associatedStorage = AssociatedStorage()
class Owner
{
// ...
}
class Dependent: KeyObjectInitializable
{
init(with keyObject: Owner)
{
//...
}
}
let owner: Owner = // ... object that is being held in memory elsewhere
let dependentForTheOwner: Dependent = associatedStorage.get(for: owner)
// later:
let dependentAgain: Dependent = associatedStorage.get(for: owner)
// `dependentForTheOwner` is absolutely the same object as `dependentAgain`
Manually initializable value
In case it’s not desireable to let the storage initialize associated value objects, it’s possible to initialize associated value “manually” and then access it on demand using similar API, with the only idfference - getter function will return nil
until associated value is explicitly initialized for given Key
object:
let associatedStorage = AssociatedStorage()
class Owner
{
// ...
}
class Dependent
{
// ...
}
let owner: Owner = // object that is being held in memory elsewhere
let _: Dependent? = associatedStorage.get(for: owner) // nil
let dependentForTheOwner: Dependent = // create somehow...
associatedStorage.set(dependentForTheOwner, for: owner)
let dependentAgain: Dependent? = associatedStorage.get(for: owner)
// `dependentForTheOwner` is absolutely the same object as `dependentAgain`
Explicitly initializable value
Another option of how to access associated value with explicit initialization is to provide initialization closure every time when request associated value from the storage. This initialization closure will be called only once for each Key
object to lazy-initialize its associated value on first access.
let associatedStorage = AssociatedStorage()
class Owner
{
// ...
}
class Dependent
{
// ...
}
let owner: Owner = // object that is being held in memory elsewhere
let dependent: Dependent = associatedStorage.get(for: owner){ key in
// ... create and return somehow an instance of Dependent here,
// with or without usage of the `key` object;
// this closure must be passed every time when access
// value objects of type `Dependent` via this particular variation
// of `get(...)` function, otherwise it's unclear how else to
// instantiate `valueObject` on first access.
}