ProgramaciónDesarrollador iOS

¿Qué es ARC en Swift? ¿Cómo evitar ciclos de retención al trabajar con closures y delegados?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

ARC (Automatic Reference Counting) — sistema de gestión automática de memoria en Swift. Con cada nueva referencia fuerte a un objeto, el contador se incrementa; al eliminarse, se decrementa. Cuando el contador es cero, el objeto se libera.

Ciclo de retención — situación en la que los objetos se refieren entre sí mediante referencias fuertes y nunca se liberan.

Formas de evitarlo:

  • Para los objetos delegados, utiliza una referencia débil:
protocol SomeDelegate: AnyObject { } class Owner { weak var delegate: SomeDelegate? }
  • Para closures, utiliza [weak self] o [unowned self]:
class Example { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doSomething() } } func doSomething() { } }

Pregunta con trampa.

¿Cuál es la diferencia entre [weak self] y [unowned self] dentro de un closure? ¿Qué tipo de referencias usar y cuándo?

Respuesta:

  • [weak self] crea una referencia opcional; self puede ser nil, por lo que generalmente se utiliza una extracción segura self?.
  • [unowned self] crea una referencia no opcional y NO incrementa el contador; si el objeto ya ha sido liberado y se intenta acceder a él, habrá un crash.
  • La elección depende de la lógica del negocio: si el closure está garantizado para vivir no más que self, se puede usar [unowned self].

Ejemplo:

someClosure = { [weak self] in self?.doTask() } // o (si self 100% vive más que closure): someClosure = { [unowned self] in doTask() }

Ejemplos de errores reales debido a la falta de conocimiento sobre el tema.


Historia

En el proyecto surgió una situación de ciclo de retención entre ViewController y su closure, vinculado al manejo de toques. ViewController hacía referencia a closure, que capturaba self con una referencia fuerte. Como resultado, el controlador y todos sus datos no se liberaban después de cerrar la pantalla. El problema se solucionó incorporando [weak self] en el closure.


Historia

Implementación del patrón delegate entre dos objetos. El delegate se declaró como una propiedad fuerte (strong). Como resultado, al intentar eliminar el objeto principal de la memoria, no se desasignó, lo que provocó una fuga de memoria. Después de cambiar el delegate a weak, el problema desapareció.


Historia

Para la animación se utilizó un closure dentro de UIView. El closure capturaba self usando [unowned self]. Cuando se eliminaban las vistas antes de que la animación terminara, la aplicación se bloqueaba debido al acceso a un self ya liberado. La solución fue utilizar [weak self] y una verificación obligatoria para asegurarse de que self no fuera nil dentro del closure.