Escaping closure è una chiusura che "esce" dal contesto della funzione chiamante (ad esempio, viene salvata per l'esecuzione asincrona).
Per impostazione predefinita in Swift, le funzioni accettano chiusure non-escaping: la chiusura viene eseguita all'interno della chiamata della funzione.
Per specificare esplicitamente escaping, si usa la parola chiave @escaping:
func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
Differenze chiave:
[weak self] o [unowned self] per prevenire perdite di memoria (retain cycle).È necessario scrivere sempre @escaping per le chiusure passate come parametri a una funzione che chiama DispatchQueue.async?
— Sì. Poiché DispatchQueue.async memorizza la chiusura fino al momento dell'esecuzione, la chiusura diventa escaping.
Esempio:
func foo(action: () -> Void) { DispatchQueue.main.async { action() // Non si compilerà: la chiusura deve essere escaping. } } // Necessario: func bar(action: @escaping () -> Void) { ... }
Storia
Il controller ha creato un riferimento forte a self all'interno di una closure escaping (ad esempio, una richiesta di rete). Il controller non veniva liberato dopo essere uscito dallo schermo — forte ciclo di retain. Soluzione: utilizzare [weak self] o [unowned self].
Storia
La funzione passava una closure a DispatchQueue.async, ma non la contrassegnava come escaping. Il progetto non si compilava, gli errori erano difficili da trovare a causa della nidificazione delle funzioni.
Storia
All'interno della closure si accedeva a un oggetto che era già deallocato al momento della chiamata della closure (si utilizzava [unowned self]). Di conseguenza — crash a runtime. Soluzione: utilizzare [weak self] e controllare nil.