la Demistificazione @fuggire, @non fuggire, @autoclosure e curry funzione
le Chiusure sono self-contained blocchi di funzionalità che possono essere passati in giro e usato nel codice.
— Apple
Le chiusure possono acquisire e memorizzare riferimenti a qualsiasi costante e variabile dal contesto in cui sono definite, noto come closing over quindi Closure. Puoi pensare a una chiusura come a una funzione che non ha un nome proprio e cattura alcun valore dal suo ambiente. Le funzioni e le chiusure sono oggetti di prima classe in Swift: puoi memorizzarli, passarli come argomenti alle funzioni e trattarli come qualsiasi altro valore o oggetto. Il passaggio di chiusure come gestori di completamento è un modello comune in molte API. La libreria Swift standard utilizza le chiusure principalmente per la gestione degli eventi e i callback.
Le funzioni sono blocchi di codice autonomi che eseguono un’attività specifica. Si assegna a una funzione un nome che identifica ciò che fa e questo nome viene utilizzato per “chiamare” la funzione per eseguire la sua attività quando necessario. Si definisce una funzione con la parola chiave func
. Le funzioni possono prendere nessuno a molti parametri, parametri variadici e restituire nessuno o più parametri.
Tipi di funzione
Il tipo di funzione è costituito dai tipi di parametro e dal tipo di ritorno della funzione. Per esempio sopra, il tipo di funzione è:(Int, Int) -> Int
Questo può essere letto come: “Una funzione che ha due parametri, entrambi di tipo Int
e che restituisce un valore di tipo Int
.”Tipo di funzione può essere impostato come parametro o tipo di ritorno di funzione.
I tipi di funzione possono essere assegnati a qualsiasi variabile come questa:
var mathFunction: (Int, Int) -> Int = add
Le funzioni sono casi speciali di chiusure. Le chiusure assumono una delle tre forme:
- Funzioni globali: hanno un nome e non possono acquisire valore.
- Funzioni nidificate: hanno un nome e possono acquisire valori dalla loro funzione di chiusura.
- Espressioni di chiusura: non hanno nome e possono acquisire valori dal loro contesto circostante.
Espressione di chiusura:
Closure può essere creato inserendo un tipo di funzione all’interno di parentesi graffe e in
parola chiave dopo il tipo di ritorno.
I nomi degli argomenti abbreviati
Gli argomenti di chiusura possono riferirsi a una posizione, ad esempio ,
,
,
e così via.
Implicita Restituisce la Chiusura:
Singola espressione chiusure implicitamente restituire il risultato della loro singola espressione omettendo il return
parola chiave dalla loro dichiarazione.
Per una chiusura di espressioni multilinea, la parola chiave return
non può essere omessa.
Chiusura finale:
Se è necessario passare un’espressione di chiusura a una funzione come ultimo argomento della funzione e l’espressione di chiusura è troppo lunga, può essere scritta come chiusura finale. Una chiusura finale viene scritta dopo le parentesi della chiamata di funzione (), anche se è ancora un argomento per la funzione. Quando si utilizza la sintassi di chiusura finale, non si scrive l’etichetta dell’argomento per la chiusura come parte della chiamata di funzione.
Se la chiusura è l’ultimo parametro di un metodo, quindi, swift permette di scrivere come questo 🖕
L’uso di finali di chiusura sintassi sintetizza la chiusura della funzionalità immediatamente dopo la funzione che la chiusura supporta, senza bisogno di avvolgere la chiusura entro il reduce(_:)
metodo esterno parentesi.
Valori di acquisizione:
Una chiusura può acquisire costanti e variabili dal contesto circostante in cui è definita. La chiusura può quindi fare riferimento e modificare i valori di tali costanti e variabili dall’interno del suo corpo, anche se l’ambito originale che definiva le costanti e le variabili non esiste più.
In Swift, la forma più semplice di una chiusura in grado di acquisire valori è una funzione nidificata, scritta all’interno del corpo di un’altra funzione. Una funzione nidificata può catturare qualsiasi argomento della sua funzione esterna e può anche catturare qualsiasi costante e variabile definita all’interno della funzione esterna.
Questa funzione makeIncrementer
accetta un argomento cioè Int come input e restituisce un tipo di funzione cioè () -> Int
. Ciò significa che restituisce una funzione, piuttosto che un semplice valore. La funzione che restituisce non ha parametri e restituisce un valore Int
ogni volta che viene chiamato.
Qui amount
è argomento, runningTotal
è dichiarato come variabile e inizializzato con 0. Funzione nidificata incrementer
cattura amount
e runningTotal
dal contesto circostante.
Vediamo makeIncrementer
in azione:
Nota: Come ottimizzazione, Swift può invece acquisire e memorizzare una copia di un valore se tale valore non viene modificato da una chiusura e se il valore non viene modificato dopo la creazione della chiusura.
Swift gestisce anche tutta la gestione della memoria coinvolta nello smaltimento delle variabili quando non sono più necessarie.
Per eliminare l’espressione di chiusura lunga nell’argomento funzione è possibile utilizzare typealias.
Chiusure non escape:
I parametri di chiusura erano in escape per impostazione predefinita prima di Swift 3. Una chiusura non sfuggirebbe al corpo della funzione se i parametri di chiusura sono contrassegnati come non escape
In Swift 3 è stato invertito. Quando si passa una chiusura come argomento della funzione, la chiusura viene eseguita con il corpo della funzione e restituisce il compilatore. Al termine dell’esecuzione, la chiusura passata esce dall’ambito e non ha più esistenza in memoria.
Il minimo che devi sapere
I parametri di chiusura non sono escape per impostazione predefinita, se vuoi sfuggire all’esecuzione della chiusura, devi usare @escape con i parametri di chiusura.
Ciclo di vita della chiusura non sfuggente:
1. Passare la chiusura come argomento di funzione, durante la chiamata di funzione.
2. Fare un po ‘ di lavoro in funzione e quindi eseguire la chiusura.
3. Funzione restituisce.
A causa di una migliore gestione della memoria e ottimizzazioni, Swift ha cambiato tutte le chiusure per essere non-escape per impostazione predefinita. CaptureList.swift
è un esempio di chiusura non sfuggente.
Nota: @ non-escape annotation si applica solo ai tipi di funzione
Escape Closures:
Si dice che una chiusura sfugge a una funzione quando la chiusura viene passata come argomento alla funzione, ma viene chiamata dopo che la funzione ritorna. Contrassegnare una chiusura con @escaping
significa che devi fare riferimento a self
esplicitamente all’interno della chiusura.
Ciclo di vita della chiusura @escape:
1. Passare la chiusura come argomento di funzione, durante la chiamata di funzione.
2. Fare qualche lavoro aggiuntivo in funzione.
3. Funzione eseguire la chiusura in modo asincrono o memorizzati.
4. Funzione restituisce.
Vediamo dove le chiusure sono di escape predefinito:
- Le variabili di tipo funzione sono escaping implicito
- typealiases sono escaping implicito
- Le chiusure opzionali sono escaping implicito
Errore comune:
Assegnazione della chiusura non escape alla chiusura di escape. Ci sono 2 modi per risolvere questo problema:
- Contrassegnare la chiusura come escape
- O mantenere il comportamento predefinito @noescape rendendo la chiusura opzionale
Autoclosures:
L’attributo @autoclosure
di Swift consente di definire un argomento che viene automaticamente inserito in una chiusura. Non richiede alcun argomento e, quando viene chiamato, restituisce il valore dell’espressione che è racchiusa al suo interno. Questa comodità sintattica consente di omettere parentesi graffe attorno al parametro di una funzione scrivendo un’espressione normale invece di una chiusura esplicita.
Ad esempio, la funzione assert(condition:message:file:line:)
accetta una chiusura automatica per i parametri condition
e message
; il parametro condition
viene valutato solo nelle build di debug e il parametro message
viene valutato solo se condition
è false
.
func assert(_ expression: @autoclosure () -> Bool,
_ message: @autoclosure () -> String) {}
Per usare @autoclosure
con @escaping
la sintassi degli attributi è:
@autoclosure @escaping () -> Bool
Chiusure vs Blocchi:
” Le chiusure Swift e i blocchi Objective-C sono compatibili in modo da poter passare le chiusure Swift ai metodi Objective-C che prevedono blocchi. Le chiusure e le funzioni Swift hanno lo stesso tipo, quindi puoi persino passare il nome di una funzione Swift. Le chiusure hanno una semantica di acquisizione simile ai blocchi, ma differiscono in un modo chiave: le variabili sono mutabili piuttosto che copiate. In altre parole, il comportamento di _ _ block in Objective-C è il comportamento predefinito per le variabili in Swift.”
Closures vs Delegates:
La soluzione dipende dal problema. Inoltre, Apple sta spostando la sua attenzione al modello di Callback. UIAlertAction
è un esempio di questo.
https://medium.com/@abhimuralidharan/functional-swift-all-about-closures-310bc8af31dd
https://medium.com/@kumarpramod017/what-do-mean-escaping-and-nonescaping-closures-in-swift-d404d721f39d
https://oleb.net/blog/2016/10/optional-non-escaping-closures/
https://swiftunboxed.com/lang/closures-escaping-noescape-swift3/
https://medium.com/@johnsundell/using-autoclosure-when-designing-swift-apis-67fe20a8b2e