Closures
Closures
Closures er en gratis Swift Academy-lektion på CoddyKit. Dette er lektion 1 af 1. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Swift Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Swift Academy-kurset indeholder 1 lektioner i alt.
Introduktion
Hej,
Closures er selvstændige kodeblokke. En closure kan sendes som parameter til kode, eller den kan bruges inde i kode.
En closure er en funktionstype. Den kan bruges ved at sende den ind som en del af koden. De minder om lambdaer i andre programmeringssprog.
Hukommelseshåndtering
Et af de vigtigste punkter er, at en closure kan gemme værdierne af konstanter og variabler i den kontekst, hvor den er defineret.
Denne lagring kaldes for at indfange værdierne.
Swift håndterer hukommelsen for os under denne lagring.
Closure-typer
Der findes forskellige typer closures.
- Globale funktioner er navngivne closures. Disse funktioner gemmer ingen værdier.
- Indlejrede funktioner kan medtage værdier fra den funktion, de er indlejret i.
- Closure-udtryk er derimod anonyme closures og kan med en enkel syntaks gemme data fra den omgivende kontekst.
Closure-syntaks
Syntaksen for closures er gjort så enkel som muligt. De vigtigste punkter er følgende.
- Parametre i closures kan udledes.
- Returværdier kan udledes.
- En closure kan returnere på én linje.
- Argumentnavne kan angives med forkortelser som $ 0 eller $ 1.
- Syntaks med trailing closure kan bruges.
Info
Closure-udtryk betyder, at closures skrives direkte i koden med fokus på syntaks og enkelhed.
Closure-syntaks
En closure-syntaks vises i eksempelkoden nedenfor.
{ (parameters) -> return type in
statements
}
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
//If we didn't use closures, our code structure would be as follows.
var reversedNames = names.sorted(by: backward)
Closure-syntaks
Med en closure behøver vi dog ikke definere en unødvendigt navngiven global closure af denne type.
Det er nok at definere et enkelt closure-udtryk som parameter. Lad os se på eksemplet.
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
print(reversedNames)
///sorted method takes closure as parameter.Nøgleordet in
Det fremgår af nøgleordet in, at closure-kroppen begynder.
Før nøgleordet in skal de parametre, som closuren modtager, og returtypen defineres.
Udledning af typen ud fra konteksten
Udledning af typer ud fra konteksten
I eksemplet ovenfor kan closure-udtrykket forstås ved at udlede parametrene og returtypen, fordi metoden sorted modtager en closure.
Derfor behøver vi ikke definere dem separat.
I dette eksempel kan man se, at værdierne i arrayet names er String-værdier, så parametrene, som closuren modtager, er af typen String.
På samme måde skal den tilknyttede closure returnere en Bool-værdi for at sortere, så returtypen udledes som Bool.
Eksempel
Det forenkler brugen nedenfor.
Pilen kan også udelades fra koden, fordi returtypen udledes.
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
print(reversedNames)Kort syntaks
Det er bedre at bruge den lange syntaks i stedet for den korte for at undgå at forvirre kodelæsere.
Syntaksen ovenfor kan forkortes endnu mere.
Returværdien kan forkortes ved at fjerne nøgleordet return fra closure-udtrykket.
/*
In this example, the return keyword has been extracted.
It already has single expression.
There is no need to express it as an extra with return.
*/
var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
print(reversedNames)Eksempel
I dette eksempel er nøgleordet return udeladt.
Der er allerede kun ét udtryk, så det er ikke nødvendigt at angive det særskilt med return.
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )Korte argumentnavne
Syntaksen kan forkortes endnu mere. I eksemplet ovenfor angav vi, at closuren tager to parametre (herunder s1 og s2). Deres typer udledes.
Nu kan vi undgå at skrive og definere disse parametre ved hjælp af forkortelser.
Da der hverken er en parameterdefinition eller en returværdi, kan nøgleordet in også udelades.
let names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { $0 > $1 } )
print(reversedNames)
// In this example $0 will shortcut the first parameter and $1 will shortcut the second parameter.Forkortet eksempel
var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: >)
print(reversedNames)
// Greater than operator takes two parameters and the rotation type is squat.TRAILING CLOSURE
Hvis den parameter, der skal sendes til en closure-funktion, er funktionens sidste argument, og closure-udtrykket er langt, kan det være mere praktisk at skrive det som en trailing closure-sætning.
Vi kan bruge trailing closure som syntaktisk sukker. Det bruges til at gøre koden mere læsbar.
Det sidste argument i de fleste iOS-metoder er en closure.
Sidste parameter
For eksempel er den sidste parameter i dette eksempel en closure.
class Animator {
class func animate(withDuration duration: Double, animations: () -> Void) {
animations()
}
}
class MyViewController {
func start() {
// With the traditional method, we can call this fund as follows.
Animator.animate(withDuration: 1, animations: { [unowned self] in
print("red")
})
}
}
MyViewController().start()Da koden ovenfor er mindre læsbar, kan den skrives sådan her
Da koden ovenfor er mindre læsbar, kan den skrives sådan her.
import Foundation
Thread.sleep(forTimeInterval: 1)
print("Background color changed to red")Eksempel
Når vi bruger trailing closure-syntaks, behøver vi ikke skrive et argumentetiket.
Fordi closures nu er blevet en del af funktionskaldet.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// function body goes here
}
// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
// closure's body goes here
})
// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
// trailing closure's body goes here
}Syntaks
Vi kan faktisk betragte trailing closure-syntaksen som syntaktisk sukker. Den gør koden mere læsbar.
/*
In the example below, animations
are expressed as closure.
*/
public class func animate(withDuration: TimeInterval, animations: () -> Void)
// In traditional usage, we need to make a call like the following.
UIView.animate(withDuration: 1, animations: { [unowned self] in
self.view.backgroundColor = UIColor.red
})
/*
In this way, both the readability of the code
increases and we avoid the use of extra brackets.
If it is as above and the last parameter of the method
is closure, Swift allows to make a call like the one below.
*/
UIView.animate(withDuration: 1) { [unowned self] in
self.view.backgroundColor = UIColor.red
}Du kan bruge koden nedenfor til at teste koden
Vi kan bruge koden nedenfor til at teste koden.
func greetThenRunClosure(name: String, closure: () -> ()) {
print("Hello, \(name)!")
closure()
}
greetThenRunClosure(name: "Paul") {
print("The closure was run")
}Værdier, der fanges af en closure
Den kan fastholde værdien af variabler, der omgiver en closure. Du kan endda ændre værdien af disse variabler fra dens egen krop og få adgang til dem.
Selv hvis disse variabler ikke befinder sig i det oprindelige omfang, hvor de blev defineret.
Fortsat
Som nævnt kan den generelt gemme disse data i indlejrede funktioner sammen med closure-udtryk. De kan gemme data fra den ydre funktion.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen())
// returns a value of 10
print(incrementByTen())
// returns a value of 20
print(incrementByTen())
// returns a value of 30Fortsættelse
Hvis du tildeler en closure som en klasseegenskab, begynder den at fastholde denne instans i closuren.
Derfor oprettes der en stærk referencecyklus mellem closuren og instansen.
Vær særligt opmærksom på hukommelseslækager.
Advarsel
Closures og funktioner er referencetyper.
@escaping
Vi kan få brug for denne brugsmåde mange steder, hvor closures bruges asynkront.
I de tidlige versioner af Swift (1 og 2) var closures i Swift-parametre escaping, og senere blev de non-escaping. Hvis vi havde brug for at sende en closure som non-escaping, skulle vi angive det specifikt.
I de senere versioner er closure-parametre blevet non-escaping for at spare hukommelse.
Nu skal vi angive @escaping, hvis vi vil definere en escaping closure.
@ESCAPING-nøgleord
Hvis vi vil kunne kalde de closures, der er tildelt en funktion, efter at funktionen har returneret, skal vi angive dem med nøgleordet @escaping.
Closures, der som standard defineres som funktionsparametre, er referencetyper, men de øger ikke referencetællingen. Når closuren kaldes, ophører dens levetid, så det er ikke nødvendigt at øge referencetællingen yderligere.
Hvis vi har brug for den closure, vi sender ind som parameter, efter funktionskaldet, skal vi muligvis angive den med @escaping.
nonEscaping
Lad os først se, hvordan en nonEscaping-closure fungerer.
Når denne closure sendes som parameter til funktionen, behandles den i funktionens krop og returneres derefter til compileren.
Når funktionen har returneret, altså når udførelsen er afsluttet, er den uden for closureens omfang og frigives fra hukommelsen.
Brug af escaping closure
Når en closure-funktion sendes som et argument, fortsætter den med at blive bevaret, selv efter at closure-funktionen har returneret, og udførelsen er afsluttet.
Den optager plads i hukommelsen, indtil closuren udføres. Der findes flere typer escaping closures.
Tillykke
Tillykke 🎉
Vi er nået til slutningen af lektionen.
Vi ses i næste lektion 😎

Lær Swift med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 122
- Lektioner
- 409
Ofte stillede spørgsmål
Er lektionen “Closures” gratis?
Ja — alle 3 lektioner i læringssporet Swift Academy, inklusive “Closures”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Swift Academy-kurset indeholder 1 lektioner i alt.
Hvad lærer jeg i “Closures”?
Closures Du øver dig i Swift Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Swift Academy?
Der kræves ingen tidligere erfaring. Swift Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 1.
Hvor lang tid tager lektionen “Closures”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Swift Academy-lektion?
Ja. Alle Swift Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.