«En la era de ARC, ¿por qué seguimos usando @autoreleasepool?»
Es una pregunta que recibo a menudo de desarrolladores junior. Es una palabra clave que claramente han visto en algún sitio, pero sorprendentemente cuesta responder de inmediato cuándo y por qué usarla.
Hoy explicaré qué es @autoreleasepool y cuándo conviene usarlo en la práctica.
Empecemos por la conclusión.
@autoreleasepooles un bloque que libera, en el momento que elijas, los objetos programados para liberarse más tarde. Su uso principal es evitar picos de memoria cuando se acumulan objetos temporales dentro de un bucle.
Veámoslo paso a paso.
¿Qué es un autorelease pool?
Empecemos por los conceptos básicos.
Objective-C cuenta desde hace tiempo con autorelease. Permite programar un objeto para que se libere «un poco más tarde, no ahora».
La lista de espera donde se alinean esos objetos programados es el autorelease pool.
Cuando el pool se drena, todos los objetos de la lista reciben release de una vez.
Entonces, ¿cuándo se vacía este pool?
En las apps de iOS, el bucle principal lo gestiona automáticamente. Al terminar cada ciclo —procesar eventos táctiles y actualizar la pantalla— vacía por completo el pool.
Por eso normalmente no tenemos que preocuparnos.
El problema aparece en los bucles
Sin embargo, hay situaciones en las que la condición «al terminar cada ciclo» se convierte en un problema.
Ocurre cuando se acumulan enormes cantidades de objetos temporales durante una sola iteración del bucle principal.
Por ejemplo, supongamos que procesamos miles de fotos en un solo bucle.
for (int i = 0; i < 5000; i++) {
// En cada iteración se crea temporalmente un objeto de imagen grande
UIImage *image = [self loadAndResizeImage:i];
[self saveThumbnail:image];
}
Mientras se ejecuta el bucle, el bucle principal no tiene oportunidad de vaciar el pool.
Por tanto, los objetos temporales pendientes de liberación se acumulan en memoria, equivalentes a 5.000 fotos.
El gráfico de memoria sube como una montaña y, en casos graves, el sistema fuerza el cierre de la app.
Cómo allanar la montaña con @autoreleasepool
La solución es sencilla: crea un pool privado dentro del bucle y vacíalo tú mismo en cada iteración.
for (int i = 0; i < 5000; i++) {
@autoreleasepool {
UIImage *image = [self loadAndResizeImage:i];
[self saveThumbnail:image];
} // Los objetos temporales se liberan en cuanto termina el bloque
}
Cuando se cierra el bloque @autoreleasepool, los objetos temporales creados dentro se limpian de inmediato.
En lugar de acumular memoria equivalente a 5.000 fotos y liberarla de golpe, sube y baja de una foto en una.
El gráfico de memoria, antes montañoso, se convierte en un patrón de dientes de sierra suave.
Así se usa en Swift
Quizá pienses: «¿Y si solo uso Swift?». Swift también tiene exactamente la misma herramienta.
Es la función autoreleasepool.
for i in 0..<5000 {
autoreleasepool {
let image = loadAndResizeImage(i)
saveThumbnail(image)
}
}
Hay un punto importante que debes tener en cuenta.
La mayoría de los objetos de Swift puro no pasan por un autorelease pool; se liberan al terminar su ámbito.
Esta herramienta resulta especialmente útil al llamar repetidamente a APIs de Foundation y UIKit basadas en Objective-C, como UIImage, Data(contentsOf:) y NSData.
Todavía hay muchas APIs que crean y devuelven objetos autoreleased internamente.
Cuándo debes usarlo
En resumen, @autoreleasepool resulta necesario en situaciones como estas:
- Cuando un bucle crea muchos objetos temporales grandes, como imágenes, archivos o cadenas
- Cuando una tarea de larga duración se ejecuta en un hilo en segundo plano sin bucle principal
- Cuando usas objetos de Objective-C en un entorno sin bucle principal, como una herramienta de línea de comandos
En cambio, normalmente no hace falta en código de UI habitual ni en la lógica de negocio común. El bucle principal ya lo gestiona correctamente.
Tampoco recomiendo envolverlo todo por costumbre sin medir. Úsalo después de comprobar un pico real en Instruments o en el gráfico de memoria de Xcode.
Preguntas frecuentes (Q&A)
P. Si ARC lo hace automáticamente, ¿por qué tengo que gestionar el pool?
ARC (Automatic Reference Counting, conteo automático de referencias) solo inserta retain y release por ti; no cambia cuándo se vacía el autorelease pool. Adelantar el momento en que se vacía sigue siendo responsabilidad del desarrollador.
P. ¿Qué es el @autoreleasepool de la función main?
Si abres main.m en un proyecto de Objective-C, verás toda la app envuelta en @autoreleasepool. Ese es el pool de nivel superior de la app. El bucle principal se ejecuta dentro y vacía los pools secundarios en cada ciclo.
P. ¿Se pueden anidar los bloques?
Sí. Los pools se apilan como una pila. Al cerrarse el bloque interno, solo se vacía el pool interno; el externo permanece intacto.
En pocas palabras, @autoreleasepool es un bloque que vacía los objetos temporales pendientes de liberación en el momento que tú decides.
Si Instruments confirma que la memoria sube como una montaña en un bucle, prueba a envolver su interior con este bloque. Verás cómo el gráfico se suaviza.
Si te interesa la historia de la transición de MRC (Manual Reference Counting, conteo manual de referencias) a ARC, también te recomiendo leer el artículo anterior, «Historia de la gestión de memoria en Objective-C». ¡Que disfrutes programando!

