Usar múltiples let-as dentro de una declaración if en Swift

144

Estoy desenvolviendo dos valores de un diccionario y antes de usarlos tengo que convertirlos y probar el tipo correcto. Esto es lo que se me ocurrió:

var latitude : AnyObject! = imageDictionary["latitude"]
var longitude : AnyObject! = imageDictionary["longitude"]

if let latitudeDouble = latitude as? Double  {
   if let longitudeDouble = longitude as? Double {
       // do stuff here
   }
}

Pero me gustaría empacar los dos si dejo consultas en uno. Para que sea algo así:

if let latitudeDouble = latitude as? Double, longitudeDouble = longitude as? Double {
    // do stuff here
}

Esa sintaxis no funciona, así que me preguntaba si había una hermosa manera de hacerlo.

Suntoch
fuente
Puede haber una manera de usar una instrucción switch para que el patrón coincida con los tipos. Echa un vistazo a los documentos :
lomokat
1
posible duplicado del uso de "if let ..." con muchas expresiones
rickster

Respuestas:

305

Actualización para Swift 3:

Lo siguiente funcionará en Swift 3:

if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
    // latitudeDouble and longitudeDouble are non-optional in here
}

Solo asegúrese de recordar que si uno de los intentos de enlaces opcionales falla, el código dentro del if-letbloque no se ejecutará.

Nota: no todas las cláusulas deben ser cláusulas 'let', puede tener cualquier serie de controles booleanos separados por comas.

Por ejemplo:

if let latitudeDouble = latitude as? Double, importantThing == true {
    // latitudeDouble is non-optional in here and importantThing is true
}

Swift 1.2:

Es posible que Apple haya leído su pregunta, porque su código esperado se compila correctamente en Swift 1.2 (en beta hoy):

if let latitudeDouble = latitude as? Double, longitudeDouble = longitude as? Double {
    // do stuff here
}

Swift 1.1 y versiones anteriores:

Aquí están las buenas noticias: puedes hacer esto totalmente. Una declaración de cambio en una tupla de sus dos valores puede usar la coincidencia de patrones para convertirlos a ambos Doubleal mismo tiempo:

var latitude: Any! = imageDictionary["latitude"]
var longitude: Any! = imageDictionary["longitude"]

switch (latitude, longitude) {
case let (lat as Double, long as Double):
    println("lat: \(lat), long: \(long)")
default:
    println("Couldn't understand latitude or longitude as Double")
}

Actualización: esta versión del código ahora funciona correctamente.

Nate Cook
fuente
me funciona en 6.1.1, @AaronBratcher, ¿por qué no a ti?
Daniel Gómez Rico
1
En Swift 1.2, ahora es posible hacer esto en una línea: stackoverflow.com/a/28418847/1698576
smithclay
En su código, tiene 2 opciones opcionales que se están desenvolviendo. ¿Se debe usar siempre así? Tengo un código diferente y confuso. if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {...}. ¿El segundo let también es vinculante opcional? Quiero decir, appya no es un opcional. ¿Derecha?
miel
1
Es. appya no es opcional, pero su windowpropiedad es (su tipo es UIWindow?), así que eso es lo que estás desenvolviendo.
Nate Cook
7

Con Swift 3, puede usar el encadenamiento opcional, la declaración de cambio o el patrón opcional para resolver su problema.


1. Uso if let(encuadernación opcional / encadenamiento opcional)

El lenguaje de programación Swift establece el encadenamiento opcional:

Se pueden encadenar varias consultas juntas, y la cadena completa falla correctamente si algún enlace en la cadena es nulo.

Por lo tanto, en el caso más simple, puede usar el siguiente patrón para usar múltiples consultas en su operación de encadenamiento opcional:

let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if let latitude = latitude as? Double, let longitude = longitude as? Double {
    print(latitude, longitude)
}

// prints: 2.0 10.0

2. Uso de tuplas y enlace de valor en una declaración de cambio

Como alternativa a un simple encadenamiento opcional, la instrucción switch puede ofrecer una solución de grano fino cuando se usa con tuplas y enlaces de valor:

let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude, longitude) {
case let (Optional.some(latitude as Double), Optional.some(longitude as Double)):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude, longitude) {
case let (latitude as Double, longitude as Double):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude as? Double, longitude as? Double) {
case let (.some(latitude), .some(longitude)):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

switch (latitude as? Double, longitude as? Double) {
case let (latitude?, longitude?):
    print(latitude, longitude)
default:
    break
}

// prints: 2.0 10.0

3. Uso de tuplas con if case(patrón opcional)

if case( patrón opcional ) proporciona una forma conveniente de desenvolver los valores de enumeración opcional. Puede usarlo con tuplas para realizar algunos encadenamientos opcionales con múltiples consultas:

let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (.some(latitude as Double), .some(longitude as Double)) = (latitude, longitude) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (latitude as Double, longitude as Double) = (latitude, longitude) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (.some(latitude), .some(longitude)) = (latitude as? Double, longitude as? Double) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
let dict = ["latitude": 2.0 as AnyObject?, "longitude": 10.0 as AnyObject?]
let latitude = dict["latitude"]
let longitude = dict["longitude"]

if case let (latitude?, longitude?) = (latitude as? Double, longitude as? Double) {
    print(latitude, longitude)
}

// prints: 2.0 10.0
Imanou Petit
fuente
5

Swift 3.0

if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
    // do stuff here
}
norbDEV
fuente
44
Debe sugerir una edición a la respuesta aceptada, no agregue otra respuesta de menor calidad.
jervine10