Saltar al contenido →

NSCache

Si a un programador Apple le piden que implemente una caché la inmensa mayoría lo hará usando un Dictionary, que no es que tenga nada de malo pero no es lo más óptimo.

Pocos conocen la existencia de NSCache, una clase del framework Foundation que sirve precisamente para gestionar cachés y que aporta cosas como la liberación de elementos cuando los recursos del sistema son bajos.

A mutable collection you use to temporarily store transient key-value pairs that are subject to eviction when resources are low.

¿Tiene ventajas usarla?

Sí que las tiene, y podríamos enurarlas en…

  1. Tiene implementantadas varias políticas de liberación de recursos y que se ejecutan de manera automática.
  2. Puedes añadir o eliminar objetos de la caché desde varios hilos. NSCache se preocupa de bloquearse para evitar problemas de acceso concurrente.
  3. Los objetos que añades a la caché no se copian, por lo que es un gran alivio para la memoria del sistema.

Como véis es mucho mejor que un Dictionary para manejar cachés.

¿Y es muy complicado usarla?

En absoluto, de hecho normalmente sólo usarás dos funciones para trabajar con NSCache.

Eso sí, tienes que tener en cuenta que tanto la clave como los valores de la caché deben ser clases, no valen estructuras.

Por ejemplo, no podemos usar como clave un String y como valor un Data, para que cumpla con la definción de NSCache deberíamos usar como clave un NSString y como valor un NSData.

También debemos saber que si queremos hacer uso del delegado de NSCache, definido en NSCacheDelegate, la clase que lo implemente debe heredar de NSObject.

Si no queremos hacer uso de este delegate podemos hacer uso de NSCache desde una clase, una estructura…

Añadir elementos a NSCache

Lo hacemos con la función setObject(_ obj: ObjectType, forKey key: KeyType) al que le pasamos el objeto que queremos almacenar en la caché y la clave con la que lo podremos recuperar posteriormente.

Sin embargo aquí encontramos una de las diferencias de NSCache con respecto al uso de Dictionary para gestionar cachés y es que podemos establacer el coste que tiene el objeto en la caché

Esto lo hacemos con la función setObject(_ obj: ObjectType, forKey key: KeyType, cost g: Int).

Por defecto el coste es el números bytes del objeto que queremos almacenar pero si por alguna circunstancia no se pueda obtener este tamaño en bytes no te preocupes en calcularlo tú o en aplicar algún algoritmo de cálculo de coste, y no porque lo diga yo, si no porque lo dicen el ingeniero que desarrolló este API.

…you should not go through the trouble of trying to compute it, as doing so will drive up the cost of using the cache

Así que lo mejor que puedes hacer es usar la primera función que hemos mencionado.

Recuperar de la caché

Fácil, lo hacemos con la función object(forKey key: KeyType) -> ObjectType? al que pasamos una clave y nos devuelve el objeto asociado si es que está presente en la caché.

Lo podemos implementar mediante un subscript

Y así podemos recuperar entradas de la cache.

¿Puedo borrar la cache?

Sin problema ninguno. Sólo tiene que usar la función removeAllObjects() para vaciar la caché por completo.

Si lo que quieres es eliminar una entrada en concreto puedes usar removeObject(forKey key: KeyType) que elimina el objeto asociado con la clave que le pasamos por parámetro.

Ahora todo junto

Lo primero que he hecho es crear un wrapper que me permite manejar la caché y los casting de una forma más sencilla

Y luego sólo queda trabajar con la cache

Y con esto tenemos una caché.

Implementado NSCacheDelegate

En caso que necesitemos saber cuándo un determinado objeto se desaloja de caché podemos implementar el protocolo NSCacheDelegate, recordando que la clase que lo haga debe heredar de NSObject.

Enlaces de interés

  • Página oficial de NSCache en la web de developers de Apple.

Publicado en Foundation