Aktualisieren von Schließungen auf Swift 3 - @escaping

75

Ich habe meinen Code auf Xcode 8.0 Beta 6 aktualisiert, bin aber bei der neuen Standardeinstellung für nicht entkommene Schließungen hängen geblieben. Im folgenden Code schlägt Xcode vor, hinzuzufügen@escaping vor completion:in der ersten Zeile der folgenden Code, aber das wird noch nicht kompiliert und geht im Kreis. * *

( EDIT : In der Tat sollte @escaping in hinzugefügt werden , nachdem completion: , wie Xcode schlägt Alarm noch zeigen kann , aber die Reinigung und Kompilieren wird es entfernen..) Wie sollte dieser Code neu geschrieben / in der aktualisierten Swift Arbeit fixiert 3 ? Ich habe mir das neue Handbuch angesehen, aber keine richtigen Codebeispiele gefunden.

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}

Jede Hilfe sehr geschätzt!

nicht chromatisch
quelle

Antworten:

58

Swift 3: Schließparameterattribute werden jetzt auf den Parameter angewendet Typ , und nicht der Parameter selbst

Vor der Swift 3, wobei die Verschluss - Attribute @autoclosureund @noescapeverwendete Attribute der Schließung seinen Parameter , jedoch sind Attribute nun den Parametertyp ; Siehe den folgenden akzeptierten Swift-Evolutionsvorschlag:

Ihre spezielle Frage bezieht sich auf das Parametertypattribut @escaping(für das dieselbe neue Regel gilt), wie im akzeptierten Swift-Evolutionsvorschlag beschrieben, damit Schließparameter standardmäßig nicht maskiert werden:

Diese Vorschläge werden jetzt beide in der Beta-Phase von Xcode 8 implementiert (siehe Versionshinweise für Xcode 8 Beta 6 ; Dev. Konto-Login für den Zugriff erforderlich)

Neu in Xcode 8 Beta 6 - Swift Compiler: Swift Language

Schließparameter werden standardmäßig nicht maskiert, anstatt explizit mit Anmerkungen versehen zu werden @noescape. Verwenden Sie @escapingdiese Option, um anzuzeigen, dass ein Schließparameter möglicherweise ausgeblendet wird. @autoclosure(escaping)ist jetzt geschrieben als @autoclosure @escaping. Die Anmerkungen @noescapeund @autoclosure(escaping)sind veraltet. (SE-0103)

...

Neu in Xcode 8 Beta - Swift- und Apple LLVM-Compiler: Swift Language

Die Attribute @noescapeund @autoclosuremüssen jetzt vor dem Parametertyp und nicht vor dem Parameternamen geschrieben werden. [SE-0049]

Daher verwenden Sie das nicht standardmäßige @escapingAttribut wie folgt: wird auf den Typ des Abschlussparameters und nicht auf den Parameter selbst angewendet

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}

(Einschließlich meiner Antwort auf eine Frage in einem positiv bewerteten Kommentar unten, da Kommentare keine dauerhaften Daten zu SO sind.)

@Cristi Băluță: "Was macht Escapeing? Ich habe diese Schlüsselwörter vor der automatischen Konvertierung von swift3 noch nie gesehen ..."

Siehe z. B. den Link zum obigen SE-0103-Evolutionsvorschlag (sowie den zitierten Text aus den Beta 6 -Versionshinweisen ): Zuvor wurden die Schließungsparameter standardmäßig maskiert (daher ist keine explizite Anmerkung zum Escaping erforderlich). sind aber jetzt standardmäßig nicht entkommen. Daher die Hinzufügung von @escapingexplizit zu kommentieren, dass ein Schließungsparameter entkommen kann (im Gegensatz zu seinem Standardverhalten). Dies erklärt auch, warum @noescapejetzt veraltet ist (das Standardverhalten muss nicht kommentiert werden).

Um zu erklären, was es bedeutet, dass ein Abschlussparameter maskiert wird, zitiere ich die Sprachreferenz - Attribute :

"Wenden Sie dieses Attribut auf den Typ eines Parameters in einer Methoden- oder Funktionsdeklaration an, um anzugeben, dass der Wert des Parameters für die spätere Ausführung gespeichert werden kann. Dies bedeutet, dass der Wert die Lebensdauer des Aufrufs überleben darf."

dfrib
quelle
Danke für die gründliche Antwort dfri. Ich habe @escaping tatsächlich an der richtigen Stelle vor dem Parameter hinzugefügt. Ich habe gerade meinen Fehler bemerkt, der darauf in der Beschreibung hinweist. Xcode würde sich immer noch beschweren, wie ich beschrieben habe, aber wenn Sie trotzdem bereinigen und kompilieren, werden die Warnungen endgültig entfernt.
Nichtautomatischer
@nontomatic gerne helfen.
dfrib
7
Was macht Flucht? Ich habe diese Schlüsselwörter vor der automatischen Konvertierung von swift3 noch nie gesehen und glaube nicht, dass ich etwas verloren habe.
Cristi Băluță
@ CristiBăluță siehe z. B. den Link zum obigen Evolutionsvorschlag für SE-0103 (sowie den zitierten Text aus den Beta 6 -Versionshinweisen ): Zuvor wurden die Schließungsparameter standardmäßig maskiert (daher ist keine Anmerkung erforderlich, dass sie maskiert wurden). sondern sind jetzt stattdessen nicht entkommen. Daher die Hinzufügung von @escapingexplizit zu kommentieren, dass ein close-Parameter entkommen kann (im Gegensatz zu seinem Standardverhalten). Dies erklärt auch, warum @noescapenicht veraltet ist (Standardverhalten muss nicht kommentiert werden).
dfrib
3
@ SagarR.Kothari Sowohl die Frage als auch die Antwort basieren auf der Tatsache, dass wir den Unterschied zwischen Flucht- und Nicht-Verschluss-Verschlüssen kennen, daher mein vorheriger Kommentar zu CristiBăluță (Antworten, warum dieses Schlüsselwort jetzt existiert). Um zu erklären, was es tut, zitiere ich die Sprache. ref.: "Wenden Sie dieses Attribut auf den Typ eines Parameters in einer Methoden- oder Funktionsdeklaration an, um anzugeben, dass der Wert des Parameters für eine spätere Ausführung gespeichert werden kann. Dies bedeutet, dass der Wert die Lebensdauer des Aufrufs überleben darf." .
dfrib
23

@noescape

Ab xcode 8 ist Beta 6 @noescapedie Standardeinstellung. Zuvor @escapingwar die Standardeinstellung. Jeder, der von früheren Versionen auf Swift 3.0 aktualisiert, kann diesen Fehler erhalten.

Sie können einen @noescapeAbschluss nicht in einer Variablen speichern . Wenn Sie einen Abschluss in einer Variablen speichern können, können Sie den Abschluss von einer beliebigen Stelle in Ihrem Code aus ausführen. Gibt jedoch an @noescape, dass der Schließungsparameter dem Funktionskörper nicht entkommen kann.

Dies führt zu einem Compilerfehler in Xcode 8

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ‼️ Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}

Dies wird ok kompilieren (explizit schreiben @escaping)

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}

Vorteile von @noescape:

  • Der Compiler kann Ihren Code für eine bessere Leistung optimieren
  • Der Compiler kann sich um die Speicherverwaltung kümmern
  • Es ist nicht erforderlich, im Verschluss einen schwachen Bezug zum Selbst zu verwenden


Weitere Informationen finden Sie unter: Machen Sie nicht entkommende Verschlüsse zur Standardeinstellung

Warif Akhand Rishi
quelle