demistificarea @ escaping, @ non-escaping, @ autoclosure și funcția curry
închiderile sunt blocuri de funcționalitate autonome care pot fi transmise și utilizate în codul dvs.
— Apple
închiderile pot capta și stoca referințe la orice constante și variabile din contextul în care sunt definite, cunoscute sub numele de închidere prin urmare închidere. Vă puteți gândi la o închidere ca fiind o funcție care nu are un nume propriu și captează orice valori din mediul său. Funcțiile și închiderile sunt obiecte de primă clasă în Swift: le puteți stoca, le puteți transmite ca argumente funcțiilor și le puteți trata ca orice altă valoare sau obiect. Trecerea închiderilor ca gestionari de finalizare este un model comun în multe API-uri. Biblioteca Swift standard folosește închideri mai ales pentru gestionarea evenimentelor și apeluri.
funcțiile sunt bucăți de cod autonome care îndeplinesc o sarcină specifică. Dați unei funcții un nume care identifică ceea ce face și acest nume este folosit pentru a „apela” funcția pentru a-și îndeplini sarcina atunci când este necesar. Definiți o funcție cu cuvântul cheie func
. Funcțiile pot lua nici unul la mai mulți parametri, parametrii variadic și a reveni nici unul sau mai mulți parametri.
tipuri de funcții
Tipul funcției este alcătuit din tipurile de parametri și tipul de retur al funcției. Pentru exemplul de mai sus, tipul funcției este:(Int, Int) -> Int
aceasta poate fi citită ca: „o funcție care are doi parametri, ambii de tip Int
și care returnează o valoare de tip Int
.”Tipul funcției poate fi setat ca parametru sau tip de retur al funcției.
tipurile de funcții pot fi atribuite oricărei variabile ca aceasta:
var mathFunction: (Int, Int) -> Int = add
funcțiile sunt cazuri speciale de închidere. Închiderile iau una din cele trei forme:
- funcții globale: au un nume și nu pot capta valoare.
- funcții imbricate: au un nume și pot capta valori din funcția lor de închidere.
- expresii de închidere: nu au nume și pot capta valori din contextul înconjurător.
Expresie De Închidere:
Închiderea poate fi creată prin introducerea unui tip de funcție în interiorul acolade și in
cuvânt cheie după tipul de retur.
numele argumentelor prescurtate
argumentele de închidere se pot referi la o poziție adică. ,
,
,
și așa mai departe.
returnări implicite de la închidere:
închiderile cu o singură expresie pot returna implicit rezultatul expresiei lor unice omițând cuvântul cheie return
din declarația lor.
pentru o închidere Expresie multilinie, return
cuvinte cheie nu pot fi omise.
Închidere Finală:
dacă trebuie să transmiteți o expresie de închidere unei funcții, deoarece ultimul argument al funcției și expresia de închidere este prea lungă, aceasta poate fi scrisă ca închidere finală. O închidere finală este scrisă după parantezele apelului funcției (), chiar dacă este încă un argument pentru funcție. Când utilizați sintaxa de închidere finală, nu scrieți eticheta argumentului pentru închidere ca parte a apelului de funcții.
dacă închiderea este ultimul parametru al unei metode, atunci swift vă permite să scrieți astfel 🖕
utilizarea sintaxei de închidere finală încapsulează perfect funcționalitatea închiderii imediat după funcția pe care o acceptă închiderea, fără a fi nevoie să înfășurați întreaga închidere în parantezele exterioare ale metodei reduce(_:)
.
captarea valorilor:
o închidere poate capta constante și variabile din contextul înconjurător în care este definită. Închiderea se poate referi apoi la și modifica valorile acelor constante și variabile din interiorul corpului său, chiar dacă domeniul inițial care a definit constantele și variabilele nu mai există.
în Swift, cea mai simplă formă de închidere care poate capta valori este o funcție imbricată, scrisă în corpul unei alte funcții. O funcție imbricată poate capta oricare dintre argumentele funcției sale exterioare și poate capta, de asemenea, orice constante și variabile definite în cadrul funcției exterioare.
această funcție makeIncrementer
acceptă un argument și anume Int ca intrare și returnează un tip de funcție, adică () -> Int
. Aceasta înseamnă că returnează o funcție, mai degrabă decât o valoare simplă. Funcția pe care o returnează nu are parametri și returnează o valoare Int
de fiecare dată când este apelată.
aici amount
este argument, runningTotal
este declarat ca variabilă și inițializat cu 0. Funcția imbricată incrementer
captează amount
și runningTotal
din contextul înconjurător.
să vedem makeIncrementer
în acțiune:
notă: Ca optimizare, Swift poate captura și stoca o copie a unei valori dacă acea valoare nu este mutată de o închidere și dacă valoarea nu este mutată după crearea închiderii.
Swift gestionează, de asemenea, toate gestionarea memoriei implicate în eliminarea variabilelor atunci când acestea nu mai sunt necesare.
pentru a scăpa de expresia de închidere lungă în Argumentul funcției, puteți utiliza typealias.
închideri care nu scapă:
parametrii de închidere scăpau în mod implicit înainte de Swift 3. O închidere nu ar scăpa de corpul funcției dacă parametrii de închidere sunt marcați ca
care nu scapă în Swift 3 a fost inversat. Când treceți o închidere ca argument al funcției, închiderea se execută cu corpul funcției și returnează compilatorul înapoi. Pe măsură ce execuția se termină, închiderea trecută iese din sfera de aplicare și nu mai există în memorie.
cel mai puțin trebuie să știți
parametrii de închidere nu scapă în mod implicit, dacă doriți să scăpați de execuția de închidere, trebuie să utilizați @escaping cu parametrii de închidere.
ciclul de viață al închiderii care nu scapă:
1. Treceți închiderea ca argument funcțional, în timpul apelului de funcții.
2. Faceți unele lucrări în funcție și apoi executați închiderea.
3. Funcția se întoarce.
datorită unei mai bune gestionări și optimizări a memoriei, Swift a schimbat toate închiderile pentru a nu scăpa în mod implicit. CaptureList.swift
este un exemplu de închidere care nu scapă.
notă: @ adnotarea care nu scapă se aplică numai tipurilor de funcții
închideri care scapă:
se spune că o închidere scapă unei funcții atunci când închiderea este transmisă ca argument funcției, dar este apelată după ce funcția revine. Marcarea unei închideri cu @escaping
înseamnă că trebuie să vă referiți la self
în mod explicit în cadrul închiderii.
ciclul de viață al închiderii @escaping:
1. Treceți închiderea ca argument de funcție, în timpul apelului de funcție.
2. Faceți unele lucrări suplimentare în funcție.
3. Funcție executați închiderea asincronă sau stocată.
4. Funcția se întoarce.
să vedem unde se închid în mod implicit:
- variabilele tipului de funcție sunt implicite care scapă
- tipealiazele sunt implicite care scapă
- închiderile opționale sunt implicite care scapă
eroare comună:
atribuirea închiderii care nu scapă închiderii care scapă. Există 2 moduri de a remedia acest lucru:
- marcați închiderea ca scăpând
- sau păstrați comportamentul @noescape implicit făcând închiderea opțională
Autoclosures:
atributul Swift @autoclosure
vă permite să definiți un argument care se înfășoară automat într-o închidere. Ea nu ia nici un argument, și atunci când este numit, returnează valoarea expresiei care este înfășurat în interiorul ei. Această comoditate sintactică vă permite să omiteți bretele în jurul parametrului unei funcții scriind o expresie normală în loc de o închidere explicită.
de exemplu, funcția assert(condition:message:file:line:)
ia o autoclosură pentru parametrii săi condition
și message
; parametrul său condition
este evaluat numai în compilările de depanare și parametrul său message
este evaluat numai dacă condition
este false
.
func assert(_ expression: @autoclosure () -> Bool,
_ message: @autoclosure () -> String) {}
pentru a utiliza @autoclosure
cu @escaping
sintaxa atributului este:
@autoclosure @escaping () -> Bool
închideri vs blocuri:
„închiderile Swift și blocurile Objective-C sunt compatibile, astfel încât să puteți trece închiderile Swift la metodele Objective-C care se așteaptă la blocuri. Închiderile și funcțiile Swift au același tip, astfel încât să puteți trece chiar și numele unei funcții Swift. Închiderile au semantică de captare similară cu blocurile, dar diferă într-un mod cheie: variabilele sunt mutabile mai degrabă decât copiate. Cu alte cuvinte, comportamentul __block în Objective-C este comportamentul implicit pentru variabilele din Swift.”
închideri vs delegați:
soluția depinde de problemă. Mai mult, Apple își schimbă accentul pe modelul de apel invers. UIAlertAction
este un exemplu în acest sens.
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