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.

bronzeado
fonte
1
possível duplicata de desembrulhar vários opcionais na instrução if
Jack
Pode haver uma maneira de usar uma instrução switch para coincidir com os tipos. Dê uma olhada no Docs :
lomokat
1
possível duplicata de Utilização "se deixar ..." com muitas expressões
Rickster

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.

Nate Cook
fonte
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
Imanou Petit
fonte
5

Swift 3.0

if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
    // do stuff here
}
norbDEV
fonte
4
Você deve sugerir uma edição da resposta aceita, não adicione outra resposta de qualidade inferior.
jervine10