Le closures in Swift sono blocchi di codice autonomi che possono catturare e mantenere riferimenti a variabili e costanti dal contesto circostante. Permettono di organizzare callback, elaborazioni asincrone e di memorizzare l'esecuzione del codice come valori delle variabili.
var counter = 0 let incrementer: () -> Void = { counter += 1 } incrementer() print(counter) // 1
[weak self], [unowned self]).self all'interno della closure.Qual è la differenza tra strong-capture e l'uso di
[weak self]o[unowned self]nella capture list della closure? Quali sono le conseguenze?
Risposta:
Se non si specifica [weak self] o [unowned self], la closure catturerà self per riferimento forte per impostazione predefinita, il che porterà a un retain cycle se la closure e self si riferiscono l'uno all'altro. [weak self] cattura self per riferimento debole (opzionale), [unowned self] per riferimento non controllato (non opzionale). Una scelta errata o l'assenza della capture list porta a perdite di memoria o crash.
class Test { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doWork() } } func doWork() { ... } }
Storia
Un programmatore non ha utilizzato la capture list in una closure all'interno di UIViewController, che avviava un caricamento dati asincrono. Di conseguenza, il controller e la sua view non venivano liberati, causando una memory leak dopo la chiusura (dismiss). L'analisi dell'infrastruttura ha mostrato centinaia di controllori "bloccati" in memoria.
Storia
La closure ha catturato self utilizzando [unowned self], ma il ciclo di vita di self è terminato prima della closure. Si è verificato un crash quando si tentava di accedere a un oggetto già liberato — l'app si chiudeva quando si cercava di lavorare con self all'interno della closure.
Storia
Nel progetto, all'interno di una closure annidata, sono state catturate due variabili: una per riferimento forte, l'altra per riferimento debole. È risultato che il riferimento weak si annullava troppo presto, e i dati necessari per il funzionamento della closure erano stati persi — il bug si è manifestato solo nel stress-test sotto carico in un contesto multithreading.