Middle
Cuéntame sobre la lista de captura en Swift.
sobes.tech AI
Respuesta de la IA
La lista de captura en Swift se utiliza para gestionar explícitamente la captura de variables por los cierres (closures). Esto ayuda a evitar ciclos fuertes de referencias, especialmente al trabajar con self en cierres utilizados dentro de clases. Los tipos principales de captura son: weak y unowned.
| Tipo de captura | Descripción | Cuándo usar |
|---|---|---|
weak |
Captura la variable como opcional, sin incrementar el contador de referencias. Su valor puede volverse nil. |
Cuando el objeto del cierre puede sobrevivir al objeto capturado. |
unowned |
Captura la variable sin incrementar el contador de referencias, pero se asume que el objeto capturado vivirá mientras exista el cierre. No es opcional. | Cuando el objeto del cierre y el objeto capturado tienen el mismo tiempo de vida, y el objeto capturado no será nil antes de que termine el cierre. |
Sintaxis de la lista de captura:
{ [lista de captura] (parámetros) -> tipoDeRetorno in
// código
}
Ejemplo de uso de weak self:
class MyClass {
var value = 0
func doSomethingLater() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self = self else { return } // Verificación de nil
self.value += 1
print("El valor ahora es \(self.value)")
}
}
}
Ejemplo de uso de unowned self:
class ViewController: UIViewController {
var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton(type: .system)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
@objc func buttonTapped() {
// no se requiere unowned en este caso, ya que el botón existe mientras exista el ViewController.
// Pero si el cierre pudiera sobrevivir al ViewController, unowned sería apropiado si
// se tiene la certeza de que self no será nil.
let action = { [unowned self] in
self.view.backgroundColor = .blue
}
action()
}
}
Se puede capturar no solo self, sino también cualquier otra variable accesible en el cierre. Por ejemplo, para guardar el valor de una variable en el momento de crear el cierre:
func createIncrementer(initialValue: Int) -> () -> Int {
var currentValue = initialValue
return { [initialValue] in // Captura initialValue por valor
currentValue += 1
print("El valor inicial era \(initialValue)") // initialValue mantiene su valor
return currentValue
}
}
let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Salida: El valor inicial era 5, luego 6
print(incrementer()) // Salida: El valor inicial era 5, luego 7