Usando vários let-as em uma instrução if no Swift


144

Estou desembrulhando dois valores de um dicionário e antes de usá-los, tenho que convertê-los e testar o tipo certo. Isto é o que eu vim com:

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
   }
}

Mas eu gostaria de empacotar os dois se deixarmos as consultas em um. Para que fosse algo assim:

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

Essa sintaxe não está funcionando, então eu queria saber se havia uma maneira bonita de fazer isso.



Pode haver uma maneira de usar uma instrução switch para coincidir com os tipos. Dê uma olhada no Docs :
lomokat

Respostas:


305

Atualização para o Swift 3:

O seguinte funcionará no Swift 3:

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

Lembre-se de que, se uma das ligações opcionais tentadas falhar, o código dentro do if-letbloco não será executado.

Nota: nem todas as cláusulas precisam ser cláusulas 'let'; você pode ter uma série de verificações booleanas separadas por vírgulas.

Por exemplo:

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

Swift 1.2:

A Apple pode ter lido sua pergunta, porque seu código esperado é compilado corretamente no Swift 1.2 (na versão beta hoje):

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

Swift 1.1 e versões anteriores:

Aqui estão as boas notícias - você pode fazer isso totalmente. Uma instrução switch em uma tupla de seus dois valores pode usar a correspondência de padrões para converter ambos ao Doublemesmo tempo:

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")
}

Atualização: Esta versão do código agora funciona corretamente.


funciona para mim no 6.1.1, @AaronBratcher por que não para você?
Daniel Gomez Rico

1
Em Swift 1.2, agora é possível fazer isso em uma linha: stackoverflow.com/a/28418847/1698576
smithclay

No seu código, você tem 2 opcionais sendo desembrulhados. É para ser usado sempre assim? Eu tenho um código confuso diferente. if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {...}. A segunda let também é obrigatória? Quero dizer, appnão é mais um opcional. certo?
Mel

1
Isto é. appnão é mais um opcional, mas sua windowpropriedade é (seu tipo é UIWindow?), e é isso que você está desembrulhando.
Nate Cook

7

Com o Swift 3, você pode usar encadeamento opcional, declaração de chave ou padrão opcional para resolver seu problema.


1. Usando if let(ligação opcional / encadeamento opcional)

A linguagem de programação Swift afirma sobre o encadeamento opcional:

Várias consultas podem ser encadeadas e a cadeia inteira falha normalmente se qualquer link da cadeia for nulo.

Portanto, no caso mais simples, você pode usar o seguinte padrão para usar várias consultas em sua operação de encadeamento 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. Usando tuplas e ligação de valor em uma instrução switch

Como alternativa a um encadeamento opcional simples, a instrução switch pode oferecer uma solução refinada quando usada com tuplas e vinculação 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. Usando tuplas com if case(padrão opcional)

if case( padrão opcional ) fornece uma maneira conveniente de desembrulhar os valores da enumeração opcional. Você pode usá-lo com tuplas para executar algum encadeamento opcional com várias 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

5

Swift 3.0

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

4
Você deve sugerir uma edição da resposta aceita, não adicione outra resposta de qualidade inferior.
jervine10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.