GitHub tag CocoaPods CocoaPods license

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 valueObjectis 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.
}