 Joseph Wright, "Gefangener"
Joseph Wright, "Gefangener" - Illustration der "starken" Gefangennahme
Die Liste der "erfassten" Werte befindet sich vor der Liste der Schließungsparameter und kann Werte aus dem Bereich auf drei verschiedene Arten "erfassen": über die Links "stark", "schwach" oder "nicht besessen". Wir verwenden es oft, hauptsächlich um starke Referenzzyklen zu vermeiden („starke Referenzzyklen“, auch bekannt als „Haltezyklen“).
Es kann für einen unerfahrenen Entwickler schwierig sein, sich für eine Methode zu entscheiden, sodass Sie viel Zeit damit verbringen können, zwischen „stark“ und „schwach“ oder zwischen „schwach“ und „nicht besessen“ zu wählen. Mit der Zeit werden Sie jedoch feststellen, dass dies die richtige Wahl ist - nur einer.
Erstellen Sie zunächst eine einfache Klasse:
class Singer { func playSong() { print("Shake it off!") } } 
Dann schreiben wir eine Funktion, die eine Instanz der 
Singer- Klasse erstellt und einen Abschluss zurückgibt, der die 
playSong () -Methode der 
Singer- Klasse 
aufruft :
 func sing() -> () -> Void { let taylor = Singer() let singing = { taylor.playSong() return } return singing } 
Schließlich können wir 
sing () überall aufrufen, um das Ergebnis des 
Spielens von playSong () zu erhalten. let singFunction = sing() singFunction() 
Infolgedessen wird die Zeile „Shake it off!“ Angezeigt.
Starke Erfassung
Sofern Sie keine explizite Erfassungsmethode angeben, verwendet Swift eine „starke“ Erfassung. Dies bedeutet, dass der Verschluss die verwendeten externen Werte erfasst und diese niemals freigibt.
Schauen wir uns noch einmal die Funktion 
sing () an
 func sing() -> () -> Void { let taylor = Singer() let singing = { taylor.playSong() return } return singing } 
Die 
Taylor-Konstante wird innerhalb einer Funktion definiert, sodass unter normalen Umständen ihr Platz freigegeben wird, sobald die Funktion ihre Arbeit beendet hat. Diese Konstante wird jedoch innerhalb des Verschlusses verwendet, was bedeutet, dass Swift seine Anwesenheit automatisch sicherstellt, solange der Verschluss selbst existiert, auch nach dem Ende der Funktion.
Dies ist eine "starke" Erfassung in Aktion. Wenn Swift 
zulässt, dass 
Taylor freigegeben wird, ist das Aufrufen eines Abschlusses unsicher - die Methode 
taylor.playSong () ist nicht mehr gültig.
"Schwache" Erfassung (schwache Erfassung)
Mit Swift können wir eine „ 
Erfassungsliste “ erstellen, 
um zu bestimmen, wie die verwendeten Werte erfasst werden. Eine Alternative zur „starken“ Erfassung ist „schwach“ und ihre Anwendung führt zu folgenden Konsequenzen:
1. „Schwach“ erfasste Werte werden vom Verschluss nicht gehalten und können daher freigegeben und auf 
Null gesetzt werden .
2. Infolge des ersten Absatzes sind „schwach“ erfasste Werte in Swift immer 
optional .
Wir modifizieren unser Beispiel mit einer „schwachen“ Erfassung und sehen sofort den Unterschied.
 func sing() -> () -> Void { let taylor = Singer() let singing = { [weak taylor] in taylor?.playSong() return } return singing } 
[schwacher Taylor] - Dies ist unsere „ 
Erfassungsliste “, ein spezieller Teil der Abschlusssyntax, in der wir Anweisungen geben, wie die Werte erfasst werden sollen. Hier sagen wir, dass 
Taylor "schwach" erfasst werden sollte, also müssen wir 
Taylor verwenden? .PlaySong () - jetzt ist es 
optional , da es jederzeit auf 
Null gesetzt werden kann.
Wenn Sie diesen Code jetzt ausführen, werden Sie 
feststellen, dass der Aufruf von 
singFunction () nicht mehr zu einer Nachricht führt. Der Grund dafür ist, dass 
Taylor nur in 
sing () existiert und der von dieser Funktion zurückgegebene Verschluss 
Taylor nicht „stark“ in sich hält.
Versuchen Sie nun, 
taylor? .PlaySong () in 
taylor! .PlaySong () zu ändern . Dies führt zu einem erzwungenen Auspacken von 
Taylor im Verschluss und dementsprechend zu einem schwerwiegenden Fehler (Auspacken von Inhalten, die 
nichts enthalten).
"Besitzerlose" Erfassung (nicht besessene Erfassung)
Eine Alternative zur "schwachen" Erfassung ist "inhaberlos".
 func sing() -> () -> Void { let taylor = Singer() let singing = { [unowned taylor] in taylor.playSong() return } return singing } 
Dieser Code endet auf ähnliche Weise abnormal mit dem oben gezeigten optional bereitgestellten optionalen - nicht besessenen 
Taylor sagt: "Ich weiß sicher, dass 
Taylor für die Dauer des Abschlusses existieren wird, daher muss ich ihn nicht im Speicher behalten." Tatsächlich wird 
Taylor fast sofort veröffentlicht und dieser Code stürzt ab.
Gehen Sie daher äußerst vorsichtig mit nicht 
besessenen Gegenständen um .
Häufige Probleme
Entwickler haben vier Probleme, wenn sie die Werterfassung in Abschlüssen verwenden:
1. Schwierigkeiten mit der Position der Erfassungsliste in dem Fall, in dem der Abschluss Parameter annimmt
Dies ist ein häufiges Problem, auf das Sie möglicherweise zu Beginn der Untersuchung von Verschlüssen stoßen, aber glücklicherweise wird Swift uns in diesem Fall helfen.
Wenn Sie die Erfassungsliste und die Abschlussparameter zusammen verwenden, wird die Erfassungsliste in eckigen Klammern angezeigt, dann die Abschlussparameter und dann das Schlüsselwort in, das den Beginn des Abschlusskörpers markiert.
 writeToLog { [weak self] user, message in self?.addToLog("\(user) triggered event: \(message)") } 
Der Versuch, nach dem Schließen eine Erfassungsliste zu erstellen, führt zu einem Kompilierungsfehler.
2. Die Entstehung eines Zyklus starker Verbindungen, der zu einem Speicherverlust führt
Wenn eine Entität A eine Entität B hat und umgekehrt, haben Sie eine Situation, die als „Aufbewahrungszyklus“ bezeichnet wird.
Betrachten Sie als Beispiel den Code:
 class House { var ownerDetails: (() -> Void)? func printDetails() { print("This is a great house.") } deinit { print("I'm being demolished!") } } 
Wir haben die 
House- Klasse definiert, die eine Eigenschaft (Closure), eine Methode und einen De-Initialisierer enthält, der eine Nachricht anzeigt, wenn eine Instanz der Klasse zerstört wird.
Erstellen Sie nun eine 
Owner- Klasse ähnlich der vorherigen, mit der Ausnahme, dass ihre Closure-Eigenschaft Informationen zum Haus enthält.
 class Owner { var houseDetails: (() -> Void)? func printDetails() { print("I own a house.") } deinit { print("I'm dying!") } } 
Erstellen Sie nun Instanzen dieser Klassen im 
do- Block. Wir brauchen keinen catch-Block, aber die Verwendung eines 
do- Blocks zerstört die Instanzen direkt nach}
 print("Creating a house and an owner") do { let house = House() let owner = Owner() } print("Done") 
Als Ergebnis werden Meldungen angezeigt: "Ein Haus und einen Eigentümer schaffen", "Ich sterbe!", "Ich werde abgerissen!", Dann "Fertig" - alles funktioniert wie es sollte.
Erstellen Sie nun eine Schleife mit starken Links.
 print("Creating a house and an owner") do { let house = House() let owner = Owner() house.ownerDetails = owner.printDetails owner.houseDetails = house.printDetails } print("Done") 
Nun erscheint die Meldung „Haus und Eigentümer erstellen“ und dann „Fertig“. Deinitializer werden nicht aufgerufen.
Dies geschah aufgrund der Tatsache, dass das Haus eine Eigenschaft hat, die auf den Eigentümer zeigt, und der Eigentümer eine Eigenschaft hat, die auf das Haus zeigt. Daher kann keiner von ihnen sicher freigegeben werden. In einer realen Situation führt dies zu Speicherverlusten, die zu einer schlechten Leistung und sogar zum Absturz der Anwendung führen.
Um die Situation zu beheben, müssen wir einen neuen Abschluss erstellen und in ein oder zwei Fällen eine „schwache“ Erfassung verwenden, wie folgt:
 print("Creating a house and an owner") do { let house = House() let owner = Owner() house.ownerDetails = { [weak owner] in owner?.printDetails() } owner.houseDetails = { [weak house] in house?.printDetails() } } print("Done") 
Es ist nicht erforderlich, beide erfassten Werte zu deklarieren. Es reicht aus, dies an einem Ort zu tun. Dadurch kann Swift bei Bedarf beide Klassen zerstören.
In realen Projekten tritt die Situation eines solch offensichtlichen Zyklus starker Verbindungen selten auf, aber dies spricht umso mehr für die Bedeutung der Verwendung einer „schwachen“ Erfassung mit kompetenter Entwicklung.
3. Die versehentliche Verwendung starker Links, normalerweise beim Erfassen mehrerer Werte
Swift verwendet standardmäßig einen starken Griff, was zu unerwartetem Verhalten führen kann.
Betrachten Sie den folgenden Code:
 func sing() -> () -> Void { let taylor = Singer() let adele = Singer() let singing = { [unowned taylor, adele] in taylor.playSong() adele.playSong() return } return singing } 
Jetzt haben wir zwei Werte, die vom Abschluss erfasst werden, und wir verwenden beide auf die gleiche Weise. Es wird jedoch nur 
Taylor als nicht besessen erfasst - 
Adele wird stark erfasst, da das nicht 
besessene Schlüsselwort für jeden erfassten Wert verwendet werden muss.
Wenn Sie dies absichtlich getan haben, ist alles in Ordnung. Wenn Sie jedoch möchten, dass beide Werte als "nicht 
besessen " 
erfasst werden , benötigen Sie Folgendes:
 [unowned taylor, unowned adele] 
4. Kopieren Sie Abschlüsse und teilen Sie erfasste Werte
Der letzte Fall, über den Entwickler stolpern, ist das Kopieren von Fehlern, da die von ihnen erfassten Daten für alle Kopien des Fehlers verfügbar werden.
Stellen Sie sich ein Beispiel für einen einfachen Abschluss vor, der die außerhalb des Abschlusses deklarierte Ganzzahlvariable 
numberOfLinesLogged erfasst, damit wir den Wert erhöhen und ihn bei jedem 
Aufruf des Abschlusses ausdrucken können:
 var numberOfLinesLogged = 0 let logger1 = { numberOfLinesLogged += 1 print("Lines logged: \(numberOfLinesLogged)") } logger1() 
Daraufhin wird die Meldung "Linien protokolliert: 1" angezeigt.
Jetzt erstellen wir eine Kopie des Abschlusses, die die erfassten Werte zusammen mit dem ersten Abschluss teilt. Wenn wir also den ursprünglichen Abschluss oder seine Kopie aufrufen, sehen wir den wachsenden Wert der Variablen.
 let logger2 = logger1 logger2() logger1() logger2() 
Dadurch werden die Meldungen "Zeilen protokolliert: 1" ... "Zeilen protokolliert: 4" 
ausgedruckt, da 
logger1 und 
logger2 auf dieselbe erfasste Variable 
numberOfLinesLogged verweisen.
Wann man ein "starkes" Capture verwendet, "schwach" und "inhaberlos"
Nachdem wir nun verstanden haben, wie alles funktioniert, versuchen wir zusammenzufassen:
1. Wenn Sie sicher sind, dass der erfasste Wert beim Schließen niemals 
Null wird , können Sie die 
Option "Nicht besessene Erfassung" verwenden . Dies ist eine seltene Situation, in der die Verwendung einer „schwachen“ Erfassung zusätzliche Schwierigkeiten verursachen kann, selbst wenn die Verwendung von Guard Let auf einen schwach erfassten Wert innerhalb des Verschlusses erfolgt.
2. Wenn Sie einen Zyklus starker Verbindungen haben (Entität A besitzt Entität B und Entität B besitzt Entität A), müssen Sie in einem der Fälle die 
„schwache Erfassung“ verwenden . Es muss berücksichtigt werden, welche der beiden Entitäten zuerst freigegeben wird. Wenn also Ansichtscontroller A Ansichtscontroller B darstellt, kann Ansichtscontroller B eine „schwache“ Verknüpfung zurück zu „A“ enthalten.
3. Wenn die Möglichkeit eines Zyklus starker Links ausgeschlossen ist, können Sie "starke" Erfassung ( 
"starke Erfassung" ) verwenden. Wenn Sie beispielsweise eine Animation ausführen, wird das Selbst innerhalb des Verschlusses, der die Animation enthält, nicht blockiert, sodass Sie eine starke Bindung verwenden können.
4. Wenn Sie sich nicht sicher sind, beginnen Sie mit einer „schwachen“ Bindung und ändern Sie diese nur bei Bedarf.
Optional - Offizieller Swift Guide:
KurzschlüsseAutomatische Linkzählung