mutating - swift 4 functions



Das Erfassen einer Strukturreferenz in einem Abschluss lässt keine Mutationen zu (2)

Ich versuche zu sehen, ob ich Strukturen für mein Modell verwenden kann und dies versuchte. Wenn ich vm.testClosure() , ändert sich der Wert von x und ich bin mir nicht sicher warum.

struct Model
{
    var x = 10.0
}


var m = Model()

class ViewModel
{
    let testClosure:() -> ()

    init(inout model: Model)
    {
        testClosure =
        {
            () -> () in
            model.x = 30.5
        }
    }
}



var vm = ViewModel(model:&m)

m.x

vm.testClosure()

m.x

https://ffff65535.com


Instanzen der Schließung erhalten ihre eigene, unabhängige Kopie des erfassten Wertes, den sie und nur sie verändern können. Der Wert wird in der Zeit der Ausführung des Abschlusses erfasst. Lass deinen leicht modifizierten Code sehen

struct Model
{
    var x = 10.0

    mutating func modifyX(newValue: Double) {
        let this = self
        let model = m
        x = newValue
// put breakpoint here
//(lldb) po model
//▿ Model
//  - x : 30.0
//
//(lldb) po self
//▿ Model
//  - x : 301.0
//
//(lldb) po this
//▿ Model
//  - x : 30.0            
    }
}

var m = Model()

class ViewModel
{

    let testClosure:() -> ()

    init(inout model: Model)
    {
        model.x = 50
        testClosure =
            { () -> () in
                model.modifyX(301)
        }
        model.x = 30
    }
}

let mx = m.x

vm.testClosure()

let mx2 = m.x

Ein inout Argument ist kein Verweis auf einen inout - es ist einfach eine Schattenkopie dieses inout , die bei Rückgabe der Funktion auf den Wert des Aufrufers zurückgeschrieben wird.

In Ihrem Code passiert, dass Ihre inout Variable die Lebensdauer der Funktion inout (indem sie in einer Closure gespeichert wird, die dann gespeichert wird). Das bedeutet, dass Änderungen an der inout Variablen nach der inout der Funktion niemals außerhalb dieser Schließung wiedergegeben werden .

Aufgrund dieses häufigen Missverständnisses über inout Argumente gab es einen Swift Evolution-Vorschlag, der nur erlaubt, dass inout Argumente von @noescape Closures erfasst werden. Ab Swift 3 wird Ihr aktueller Code nicht mehr kompiliert.

Wenn Sie Referenzen in Ihrem Code wirklich weitergeben müssen, sollten Sie Referenztypen verwenden (machen Sie Ihr Model einer class ). Obwohl ich vermute, dass Sie wahrscheinlich in der Lage sein werden, Ihre Logik umzuformen, um zu vermeiden, dass Referenzen zuerst weitergegeben werden (aber ohne Ihren eigentlichen Code zu sehen, ist es unmöglich, ihn zu beraten).

( Edit: Seit der inout dieser Antwort können inout Parameter jetzt als Pass-by-Reference kompiliert werden, was man an der inout SIL oder IR sehen kann. Sie können sie jedoch nicht als solche behandeln, da sie existieren keine Garantie, dass der Wert des Anrufers nach dem Funktionsaufruf gültig bleibt.)





mutating-function