Tengo una función con un inout
parámetro: enabled: Bool
El objeto al que me refiero (lo sé inout
no es técnicamente una referencia ...) y la configuración con este método es una propiedad almacenada en un UIViewController
var enabled = false
Tengo varios booleanos que desencadenan diferentes cosas, y quiero usar un método para configurarlos.
Entonces llamo al método:
self.determineEnabled(&self.enabled)
A continuación se muestra el código, y he usado comentarios para explicar lo que está sucediendo.
Código:
func determineEnabled(inout enabled: Bool) {
if enabled == false {
enabled = true
//self.enabled equals true now. This works. Its not in a closure...
} else {
let delete = UIAlertAction(title: "Disable", style: .Destructive, handler: { (action) -> Void in
enabled = false
print(self.enabled)
//This doesn"t work. the inout variable equals FALSE
//self.enabled equals true
//If I set self.enabled = false.. Then it works, but I"m using a method because my app could have dozens of these enabled bools on this view controller.
let alertController = UIAlertController(title: "Change Bool", message: "", preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(delete)
self.presentViewController(alertController, animated: true, completion: nil)
}
}
Mi aplicación es obviamente más compleja que esta porción de código, pero puedo verificar que este problema existe dentro de esta tirada de código.
Seré honesto porque no entiendo los cierres tanto como quisiera.
Pero si puedo usar self.enabled
para cambiar correctamente el valor de habilitado, ¿qué impide que Swift cambie la configuración de la variable habilitada inout?
ACTUALIZAR:
Aquí hay un enlace de los documentos que mencionan específicamente mi problema: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545
"No hay copia al final de los cierres ofunciones anidadas Esto significa que si se llama a un cierre después de que la función regrese, cualquier cambio que haga el cierre en los parámetros de entrada y salida no se copiará nuevamente al original ".
Evolución rápida sobre el tema: https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md
Respuestas
3 para la respuesta № 1En Swift, las funciones son cierres. Los cierres capturan el estado. En el momento nos encontramos con la función anónima que contiene el código print(self.enabled)
, self.enabled
es true
. Sabemos que, si no fuera así, no estaríamos aquí en absoluto (estaríamos en el primer ala de la condición, if enabled == false
) Por lo tanto cuando print(self.enabled)
luego se ejecuta, imprimirá true
, porque ese era el estado de las cosas cuando capturó su valor.
2 para la respuesta № 2
Lo dijiste tú mismo en tu pregunta;
Sé que inout no es técnicamente una referencia
Del libro de Apple Swift
Un parámetro de entrada tiene un valor que se pasa en a la función, es modificado por la función y se devuelve fuera de la función para reemplazar el valor original.
Está modificando el valor en un cierre que se ejecuta algún tiempo después cuando el usuario interactúa con la alerta. En este punto determineEnabled
ya ha devuelto y almacenado el valor de inout
parámetro.
Si una inout
parámetro estaba una referencia, como un puntero estilo C, luego enabled
estaría apuntando a un trozo de memoria que almacena self.enabled
y cuando el valor se modificó en el cierre, self.enabled
sería modificado
Puede ver cómo funciona esto si crea una clase simple con una propiedad booleana y luego pasa una instancia de esta clase a su determineEnabled
función (sin usar inout
) Ya que los objetos son pasado por referencia, una actualización posterior a la propiedad del objeto en el cierre será visible en cualquier lugar donde se use la misma referencia de objeto;