2016-01-20 7 views
5

Im Test Swift 2.0 und das neue Schlüsselwort defer in einem Spielplatz in Swift funktionierte:verschieben in Funktion nicht 2.0

func branch() -> String { 

    var str = "" 

    defer { str += "xxx" } 
    str += "1" 

    let counter = 3; 

    if counter > 0 { 
     str += "2" 
     defer { str += "yyy" } 
     str += "3" 
    }  
    str += "4" 

    return str  
} 

let bran = branch() 

I bran"123yyy4xxx" zu erwarten, aber es ist eigentlich "123yyy4"

Warum hat meine Verschiebung (str += "xxx") funktioniert nicht wie erwartet?

+1

es funktioniert, aber die 'defer' aufgerufen wird _after_ der Umfang abläuft, also zunächst die 'return str' wird aufgerufen, dann läuft der scope aus und es ruft den' defer' auf und fügt das '" xxx "' zu der lokalen Instanz hinzu, die _ nach der Rückgabe des Wertes passiert. – holex

Antwort

7

Eine Defer-Anweisung verzögert die Ausführung, bis der aktuelle Bereich beendet wird.

Das was Apfel sagt. Daher wird die Defer-Anweisung nach der Return-Anweisung ausgeführt. Deshalb können Sie das erwartete Ergebnis nicht sehen.

5

Erstens: die defer wird ausgeführt, wie Sie deutlich sehen können, wenn Sie eine print(str) hinzufügen. Jetzt

zu erklären, warum der zurückgegebene Wert nicht den geänderten Wert widerspiegelt:
Der Grund dafür ist, dass String unveränderlich ist - wann immer Sie str += something schreiben Sie eine völlig neue String Instanz erstellen und speichern es in str.

Wenn Sie return str schreiben, wird die aktuelle Instanz str zurückgegeben, die 123yyy4 lautet. Dann wird der defer aufgerufen und der String123yyy4xxx dem str das völlig neue und nicht verwandte zugewiesen. Aber das ändert nichts an dem vorherigen String Objekt, das in str gespeichert ist, es überschreibt es einfach und beeinflusst daher nicht die return, die bereits "passiert" ist.

Wenn Sie Ihre Methode ändern NSMutableString stattdessen verwenden Sie auf der gleichen Instanz und das Ergebnis wird daher korrekt ausgegeben 123yyy4xxx immer funktionieren wird:

func branch() -> NSMutableString { 
    var str = NSMutableString() 
    defer { str.appendString("xxx") } 
    str.appendString("1") 
    let counter = 3; 
    if counter > 0 { 
     str.appendString("2") 
     defer { str.appendString("yyy") } 
     str.appendString("3") 
    } 
    str.appendString("4") 
    return str 
} 


let bran1 = branch() 

In diesem Code gibt die Rückkehr der in str gespeichert Instanz und der Defer ändert das instance, es weist keine neue Instanz zu, aber ändert die bereits vorhandene.

Zur Erläuterung halber können Sie versuchen, die Speicheradresse str in verschiedenen Stadien zu lesen:

  • zum Zeitpunkt der return
  • vor str im defer Block
  • , nachdem es
  • -Änderungs

Für die NSMutableString alle drei Fälle ergeben die gleiche Speicheradresse maintin g dass die Instanz gleich bleibt. Die Datei String gibt jedoch zwei verschiedene Speicheradressen aus, was dazu führt, dass die zurückgegebene Zeichenfolge auf someAddress und die zurückgesetzte auf someOtherAddress zeigt.

+3

Beachten Sie, dass 'unsafeAddressOf()' mit einer Swift-Zeichenfolge (oder einem beliebigen Nicht-Klassen-Typ) völlig bedeutungslos ist. Sie gibt die Adresse eines vorübergehend überbrückten NSS-Strings zurück: http://stackoverflow.com/questions/32638879/swift-strings- Und-Speicheradressen. –

+0

@MartinR hmm:/any Idee, was ich stattdessen verwenden sollte, um die Speicheränderung der String-Instanz zu visualisieren? – luk2302

7

Greg ist richtig, und wenn Sie gleiche Ergebnis mit Ihrem Code erhalten möchten, dann können Sie es auf diese Weise tun:

var str = "" 

func branch() { 

    str = "" 
    defer { str += "xxx" } 
    str += "1" 


    let counter = 3 

    if counter > 0 { 
     str += "2" 
     defer { str += "yyy" } 
     str += "3" 
    } 
    str += "4" 

} 

branch() 
str //"123yyy4xxx" 
+2

Globale Variablen basierte Lösungen sind fast nie gute Lösungen. Sie haben auch vergessen, die 'str'-Variable zurückzusetzen, also ruft' branch() 'mehrmals auf, führt zu unterschiedlichen Ergebnissen. – Cristik

+0

Code aktualisiert und danke für Ihren Vorschlag. –