← Swift EspañolChapter 12 of 13

Gestion de Memoria

## Objetivos de Aprendizaje - Comprender conceptos basicos de ARC - Trabajar con referencias weak y unowned - Evitar ciclos de retencion - Dominar patrones de gestion de memoria ## Conteo Automatico de Referencias ### Como Funciona ARC Swift usa Conteo Automatico de Referencias (ARC) para gestionar memoria: ```swift class Persona { var nombre: String init(nombre: String) { self.nombre = nombre } deinit { print("\(nombre) esta siendo desasignado") } } var persona1: Persona? var persona2: Persona? var persona3: Persona? persona1 = Persona(nombre: "Alicia") // Conteo de referencias: 1 persona2 = persona1 // Conteo de referencias: 2 persona3 = persona1 // Conteo de referencias: 3 persona1 = nil // Conteo de referencias: 2 persona2 = nil // Conteo de referencias: 1 persona3 = nil // Conteo de referencias: 0 -> DESASIGNADO ``` ### Reglas de Conteo de Referencias | Accion | Efecto | |--------|--------| | Asignar a variable | +1 referencia | | Variable sale del alcance | -1 referencia | | Asignar nil | -1 referencia | | Copiar referencia | +1 referencia | ## Referencias Fuertes ### Comportamiento Predeterminado ```swift class Profesor { var nombre: String init(nombre: String) { self.nombre = nombre } deinit { print("\(nombre) desasignado") } } let profesor = Profesor(nombre: "Sr. Garcia") // Referencia fuerte por defecto ``` ### Ciclo de Vida de Instancia de Clase ```swift class Cliente { let nombre: String init(nombre: String) { self.nombre = nombre } deinit { print("\(nombre) esta siendo desasignado") } } func crearCliente() { let cliente = Cliente(nombre: "Alicia") print("\(cliente.nombre) creado") } crearCliente() // Salida: // Alicia creado // Alicia esta siendo desasignado ``` ## Referencias Debiles ### Declaracion ```swift weak var delegate: AlgunDelegate? ``` ### Caso de Uso: Delegates ```swift protocol DelegatePadre: AnyObject { func hijoActualizado() } class Padre { weak var delegate: DelegatePadre? func actualizar() { delegate?.hijoActualizado() } } class Hijo { var padre: Padre? init() { padre = Padre() padre?.delegate = self } deinit { print("Hijo desasignado") } } extension Hijo: DelegatePadre { func hijoActualizado() { print("Actualizado!") } } var hijo: Hijo? = Hijo() hijo = nil // Hijo desasignado correctamente - sin ciclo de retencion ``` ### Reglas de Referencia Debil - Siempre opcional (`var`) - Se establece a `nil` cuando el objeto referenciado se desasigna - Usar para delegates y referencias padre ## Referencias Unowned ### Declaracion Unowned ```swift unowned var referencia: AlgunTipo ``` ### Caso de Uso: Referencias Capturadas ```swift class Cliente { let nombre: String var tarjeta: TarjetaCredito? init(nombre: String) { self.nombre = nombre } deinit { print("Cliente \(nombre) desasignado") } } class TarjetaCredito { let numero: Int unowned let propietario: Cliente init(numero: Int, propietario: Cliente) { self.numero = numero self.propietario = propietario } deinit { print("Tarjeta \(numero) desasignada") } } var cliente: Cliente? = Cliente(nombre: "Alicia") cliente?.tarjeta = TarjetaCredito(numero: 1234, propietario: cliente!) // El unowned owner de TarjetaCredito no aumenta el conteo de retencion cliente = nil // Cliente desasignado, luego TarjetaCredito desasignada ``` ### unowned vs weak | Caracteristica | weak | unowned | |----------------|------|---------| | Tipo | Opcional | No opcional | | Valor cuando se desasigna | nil | Crashea si se accede | | Usar cuando | Puede ser nil | Nunca nil | | Uso tipico | Delegates | Padre/hijo | ## Ciclos de Retencion ### Que es un Ciclo de Retencion? ```swift class Persona { var nombre: String var amigo: Persona? // Fuerte por defecto init(nombre: String) { self.nombre = nombre } deinit { print("Persona \(nombre) desasignada") } } var alice: Persona? var bob: Persona? alice = Persona(nombre: "Alicia") bob = Persona(nombre: "Bob") alice?.amigo = bob // Alice -> Bob (fuerte) bob?.amigo = alice // Bob -> Alice (fuerte) // Ciclo de retencion: Alice <-> Bob // Ninguno sera nunca desasignado! ``` ### Romper el Ciclo ```swift class Persona { var nombre: String weak var amigo: Persona? // weak rompe el ciclo init(nombre: String) { self.nombre = nombre } deinit { print("Persona \(nombre) desasignada") } } ``` ## Capturas de Closures ### Closures y Referencias ```swift class ManejadorClosure { var valor = 10 lazy var closure: () -> Int = { return self.valor // Captura fuerte de self } } ``` ### Listas de Captura ```swift class Manejador { var valor = 10 lazy var closureDebil: () -> Int = { [weak self] in return self?.valor ?? 0 // Captura debil } lazy var closureUnowned: () -> Int = { [unowned self] in return self.valor // Captura unowned } } ``` ### Por Que Listas de Captura? ```swift class MiControladorVista { var datos: [String] = [] func cargarDatos() { // Sin lista de captura - CICLO DE RETENCION! // completion: () -> Void = { self.datos = [...] } // Con lista de captura - seguro API.obtener { [weak self] resultado in self?.datos = resultado } } } ``` ## Patrones de Gestion de Memoria ### Patron Delegate ```swift protocol DelegadoManejador: AnyObject { func completo() } class Manejador { weak var delegate: DelegadoManejador? } ``` ### Referencias Padre-Hijo ```swift class Padre { var hijos: [Hijo] = [] func agregarHijo(_ hijo: Hijo) { hijos.append(hijo) hijo.padre = self // Fuerte } } class Hijo { weak var padre: Padre? // Debil - previene ciclo } ``` ### Patron Fuente de Datos ```swift class CeldaTablaVista { weak var fuenteDatos: FuenteDatosTablaVista? } ``` ## Depurar Problemas de Memoria ### Depurador de Grafos de Memoria (Xcode) 1. Ejecutar app en modo debug 2. Debug > Depurar Grafos de Memoria 3. Buscar ciclos y fugas ### Instruments - Instrumento Allocations - Instrumento Leaks - Instrumento Core Allocation ### Sintomas Comunes - Memoria sigue creciendo - deinit nunca llamado - App usando mas RAM de lo esperado ## Mejores Practicas ### Hacer ```swift // Usar weak para delegates weak var delegate: MiDelegate? // Usar weak/weak self en closures algunLlamadoAsincrono { [weak self] resultado in self?.manejar(resultado) } // Usar unowned cuando es seguro lazy var closure: () -> String = { [unowned self] in return self.id } ``` ### No Hacer ```swift // No crear ciclos de referencia fuertes class A { var b: B? } class B { var a: A? // Ciclo si ambos se referencian fuertemente } // No usar unowned cuando es opcional // MAL: unowned var referenciaOpcional: String? (error de compilador) ``` ## Tipos Valor vs Tipos Referencia ### Tipos Valor (Struct, Enum) ```swift struct Punto { var x: Int var y: Int } var p1 = Punto(x: 1, y: 2) var p2 = p1 // Copia! Sin conteo de referencias p2.x = 10 print(p1.x) // 1 (sin cambios) print(p2.x) // 10 ``` ### Tipos Referencia (Class) ```swift class PuntoClase { var x: Int var y: Int init(x: Int, y: Int) { self.x = x self.y = y } } var p1 = PuntoClase(x: 1, y: 2) var p2 = p1 // Misma referencia! p2.x = 10 print(p1.x) // 10 (cambiado!) print(p2.x) // 10 ``` ## Resumen - ARC gestiona memoria automaticamente para instancias de clase - Referencias fuertes aumentan el conteo de retencion - Referencias debiles (`weak var`) no aumentan el conteo, pueden ser nil - Referencias unowned (`unowned var`) no aumentan el conteo, nunca nil - Ciclos de retencion ocurren con referencias circulares fuertes - Usar weak para delegates y referencias padre - Usar listas de captura en closures: `[weak self]` o `[unowned self]` - Tipos valor (structs) son copiados, no contados por referencia - Tipos referencia (classes) comparten referencias

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →