vestido subir reparar que pantalon oxidado metalico lubricar destrabar deslizador como cierre baja atorar arreglar abre swift struct closures mutating-function

swift - reparar - como subir el cierre de un pantalon



Capturar una referencia de estructura en un cierre no permite que ocurran mutaciones (3)

Las instancias del cierre obtendrán su propia copia independiente del valor capturado que él, y solo él, puede modificar. El valor se captura en el momento de ejecutar el cierre. Deje ver su código ligeramente modificado

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

Estoy intentando ver si puedo usar estructuras para mi modelo y estoy intentando esto. Cuando llamo a vm.testClosure() , no cambia el valor de x y no estoy seguro de por qué.

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


Un argumento inout no es una referencia a un tipo de valor; es simplemente una copia inout de ese tipo de valor, que se escribe de nuevo en el valor de la persona que llama cuando la función retorna.

Lo que está sucediendo en su código es que su variable inout está escapando de la vida de la función (al capturarse en un cierre que luego se almacena), lo que significa que cualquier cambio en la variable inout después de que la función haya retornado nunca se reflejará fuera de ese cierre .

Debido a esta idea equivocada común sobre los argumentos inout , se ha presentado una propuesta de Swift Evolution para permitir que los argumentos inout sean capturados por los cierres de @noescape . A partir de Swift 3, su código actual ya no se compilará.

Si realmente necesita pasar referencias en su código, entonces debe usar tipos de referencia (haga de su Model una class ). Aunque sospecho que probablemente será capaz de refactorizar su lógica para evitar pasar referencias en primer lugar (sin embargo, sin ver su código real, es imposible aconsejarlo).

( Editar: desde publicar esta respuesta, los parámetros inout ahora se pueden compilar como una referencia paso a paso, que se puede ver mirando el SIL o IR emitido. Sin embargo, no puede tratarlos como tales debido a que hay no hay garantía de que el valor de la persona que llama seguirá siendo válido después de la llamada a la función).


Esto es lo que dice Apple sobre eso.

Clases y estructuras

Un tipo de valor es un tipo que se copia cuando se asigna a una variable o constante, o cuando se pasa a una función. [...] Todas las estructuras y enumeraciones son tipos de valores en Swift

Métodos

Las estructuras y las enumeraciones son tipos de valores. Por defecto, las propiedades de un tipo de valor no se pueden modificar desde sus métodos de instancia.

Sin embargo, si necesita modificar las propiedades de su estructura o enumeración dentro de un método en particular, puede optar por mutar el comportamiento de ese método. El método puede luego mutar (es decir, cambiar) sus propiedades desde dentro del método, y cualquier cambio que realice se vuelve a escribir en la estructura original cuando finaliza el método. El método también puede asignar una instancia completamente nueva a su propia propiedad implícita, y esta nueva instancia reemplazará la existente cuando el método finalice.

Tomado de aquí