avmystifiera @ escaping, @non-escaping, @autoclosure och curry funktion
stängningar är fristående block av funktionalitet som kan skickas runt och användas i din kod.
— Apple
stängningar kan fånga och lagra referenser till alla konstanter och variabler från det sammanhang där de definieras, känd som stängning över därmed stängning. Du kan tänka på en stängning som en funktion som inte har ett eget namn och fångar några värden från sin miljö. Funktioner och stängningar är förstklassiga objekt i Swift: du kan lagra dem, skicka dem som argument till funktioner och behandla dem som något annat värde eller objekt. Att passera stängningar som slutförandehanterare är ett vanligt mönster i många API: er. Standard Swift library använder nedläggningar främst för händelsehantering och återuppringningar.
funktioner är fristående bitar av kod som utför en specifik uppgift. Du ger en funktion ett namn som identifierar vad den gör, och det här namnet används för att ”ringa” funktionen för att utföra sin uppgift när det behövs. Du definierar en funktion med nyckelordet func
. Funktioner kan ta Ingen till många parametrar, variadiska parametrar och returnera ingen eller flera parametrar.
Funktionstyper
Funktionstyp består av parametertyperna och funktionstypen för funktionen. För ovanstående exempel är funktionstypen:(Int, Int) -> Int
detta kan läsas som: ”en funktion som har två parametrar, båda av typen Int
och som returnerar ett värde av typen Int
.”Funktionstyp kan ställas in som parameter eller retur typ av funktion.
Funktionstyper kan tilldelas någon variabel som denna:
var mathFunction: (Int, Int) -> Int = add
funktioner är speciella fall av stängningar. Nedläggningar tar en av tre former:
- globala funktioner: de har ett namn och kan inte fånga värde.
- kapslade funktioner: de har ett namn och kan fånga värden från sin omslutande funktion.
- Stängningsuttryck: de har inte namn och kan fånga värden från sitt omgivande sammanhang.
Stängningsuttryck:
stängning kan skapas genom att sätta en funktionstyp inuti lockiga hängslen och in
nyckelord efter returtypen.
Shorthand Argument Names
Stängningsargument kan hänvisa till en position dvs. ,
,
,
och så vidare.
implicita avkastningar från stängning:
Enkeluttrycksförslutningar kan implicit returnera resultatet av deras enda uttryck genom att utelämna nyckelordet return
från deras deklaration.
för ett flerradigt uttryck stängning, return
sökord kan inte utelämnas.
Avslutande Stängning:
om du behöver skicka ett stängningsuttryck till en funktion eftersom funktionens sista argument och stängningsuttryck är för långt kan det skrivas som avslutande stängning. En avslutande stängning skrivs efter funktionsanropets parenteser (), även om det fortfarande är ett argument för funktionen. När du använder syntaxen för avslutande stängning skriver du inte argumentetiketten för stängningen som en del av funktionsanropet.
om stängning är den sista parametern till en metod tillåter swift dig att skriva så här 🖕
användningen av avslutande stängningssyntax inkapslar noggrant stängningens funktionalitet omedelbart efter den funktion som Stängningen stöder, utan att behöva linda hela Stängningen inom reduce(_:)
– metodens yttre parenteser.
fånga värden:
en stängning kan fånga konstanter och variabler från det omgivande sammanhanget där det definieras. Stängningen kan sedan hänvisa till och ändra värdena för dessa konstanter och variabler från dess kropp, även om det ursprungliga omfånget som definierade konstanterna och variablerna inte längre existerar.
i Swift är den enklaste formen av en stängning som kan fånga värden en kapslad funktion, skriven i kroppen av en annan funktion. En kapslad funktion kan fånga någon av dess yttre funktionens argument och kan också fånga alla konstanter och variabler som definieras inom den yttre funktionen.
denna makeIncrementer
– funktion accepterar ett argument, dvs Int som inmatning och returnerar en funktionstyp, dvs () -> Int
. Det betyder att det returnerar en funktion snarare än ett enkelt värde. Funktionen den returnerar har inga parametrar och returnerar ett Int
– värde varje gång det anropas.
här amount
är argument, runningTotal
deklareras som variabel och initieras med 0. Kapslad funktion incrementer
fångar amount
och runningTotal
från omgivande sammanhang.
Låt oss se makeIncrementer
i aktion:
notera: Som en optimering kan Swift istället fånga och lagra en kopia av ett värde om det värdet inte muteras av en stängning och om värdet inte muteras efter att Stängningen har skapats.
Swift hanterar också all minneshantering som är involverad i bortskaffande av variabler när de inte längre behövs.
för att bli av med långt stängningsuttryck i Funktionsargument kan du använda typealias.
stängningar som inte flyr:
Stängningsparametrar flydde som standard före Swift 3. En stängning skulle inte undkomma funktionskroppen om stängningsparametrar är markerade som icke-flyktande
i Swift 3 har den blivit omvänd. När du passerar en stängning som Funktionsargument, stängs Stängningen med funktionens kropp och returnerar kompilatorn tillbaka. När utförandet slutar går den passerade Stängningen utanför räckvidden och har ingen mer existens i minnet.
det minsta du behöver veta
Stängningsparametrar är icke-flyktande som standard, om du vill undvika stängningsexekveringen måste du använda @escaping med stängningsparametrarna.
livscykel för den icke-flyktande Stängningen:
1. Passera Stängningen som ett Funktionsargument under funktionsanropet.
2. Gör lite arbete i funktion och utför sedan Stängningen.
3. Funktionen returnerar.
på grund av bättre minneshantering och optimeringar har Swift ändrat alla stängningar för att inte fly som standard. CaptureList.swift
är ett exempel på icke-flyktig stängning.
Obs: @ annotering som inte kan fly gäller endast funktionstyper
Utrymningsstängningar:
en stängning sägs undkomma en funktion när Stängningen skickas som ett argument till funktionen, men anropas efter att funktionen returnerar. Att markera en stängning med @escaping
betyder att du måste hänvisa till self
uttryckligen inom Stängningen.
livscykel för @escaping-Stängningen:
1. Passera Stängningen som Funktionsargument under funktionsanropet.
2. Gör lite extra arbete i funktion.
3. Funktion utför Stängningen asynkront eller lagras.
4. Funktionen returnerar.
Låt oss se var stängningar som standard flyr:
- variabler av funktionstyp är implicit escaping
- typealiases är implicit escaping
- valfria stängningar är implicit escaping
vanligt fel:
tilldela icke-escaping-stängning till escaping-stängning. Det finns 2 sätt att fixa detta:
- markera stängning som escaping
- eller behåll standard @ noescape-beteendet genom att göra Stängningen valfri
Autoclosures:
Swifts @autoclosure
attribut gör att du kan definiera ett argument som automatiskt blir inslaget i en stängning. Det tar inga argument, och när det kallas returnerar det värdet på uttrycket som är inslaget inuti det. Denna syntaktiska bekvämlighet kan du utelämna hängslen runt en funktions parameter genom att skriva ett normalt uttryck i stället för en explicit stängning.
till exempel tar funktionen assert(condition:message:file:line:)
en autoklosure för dess condition
och message
parametrar; dess condition
parameter utvärderas endast i debug builds och dess message
parameter utvärderas endast om condition
är false
.
func assert(_ expression: @autoclosure () -> Bool,
_ message: @autoclosure () -> String) {}
för att använda @autoclosure
med @escaping
attribut syntax är:
@autoclosure @escaping () -> Bool
stängningar vs Block:
” Swift-stängningar och Objective-C-Block är kompatibla så att du kan skicka Swift-stängningar till Objective-C-metoder som förväntar sig block. Swift-stängningar och funktioner har samma typ så att du till och med kan skicka namnet på en Swift-funktion. Stängningar har liknande infångningssemantik som block men skiljer sig på ett viktigt sätt: variabler är muterbara snarare än kopierade. Med andra ord är beteendet hos __block i Objective-C standardbeteendet för variabler i Swift.”
stängningar vs delegater:
lösningen beror på problemet. Dessutom flyttar Apple sitt fokus till Återuppringningsmönster. UIAlertAction
är ett exempel på detta.
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