Verwenden mehrerer Let-As innerhalb einer if-Anweisung in Swift

144

Ich packe zwei Werte aus einem Wörterbuch aus und bevor ich sie verwende, muss ich sie umwandeln und auf den richtigen Typ testen. Folgendes habe ich mir ausgedacht:

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

Aber ich würde die beiden gerne packen, wenn ich Anfragen in eine lassen würde. Damit es so etwas würde:

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

Diese Syntax funktioniert nicht, also habe ich mich gefragt, ob es einen schönen Weg gibt, das zu tun.

suntoch
quelle
1
Mögliches Duplikat des Auspackens mehrerer Optionen in der if-Anweisung
Jack
Es kann eine Möglichkeit geben, eine switch-Anweisung zu verwenden, um Musterübereinstimmungen mit den Typen vorzunehmen.
Werfen
1
Mögliches Duplikat von Using "if let ..." mit vielen Ausdrücken
Rickster

Antworten:

305

Update für Swift 3:

In Swift 3 funktioniert Folgendes:

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

Denken Sie daran, dass der Code im if-letBlock nicht ausgeführt wird , wenn eine der versuchten optionalen Bindungen fehlschlägt .

Hinweis: Die Klauseln müssen nicht alle 'let'-Klauseln sein. Sie können eine beliebige Reihe von Booleschen Prüfungen durch Kommas trennen.

Beispielsweise:

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

Swift 1.2:

Apple hat Ihre Frage möglicherweise gelesen, weil Ihr erhoffter Code in Swift 1.2 (heute in der Beta) ordnungsgemäß kompiliert wird:

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

Swift 1.1 und früher:

Hier sind die guten Nachrichten - Sie können dies voll und ganz tun. Eine switch-Anweisung für ein Tupel Ihrer beiden Werte kann mithilfe des Mustervergleichs beide Doublegleichzeitig umwandeln:

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

Update: Diese Version des Codes funktioniert jetzt ordnungsgemäß.

Nate Cook
quelle
es funktioniert für mich in 6.1.1, @AaronBratcher, warum nicht für Sie?
Daniel Gomez Rico
1
In Swift 1.2 ist dies jetzt in einer Zeile möglich: stackoverflow.com/a/28418847/1698576
smithclay
In Ihrem Code werden 2 Optionen ausgepackt. Soll es immer so verwendet werden? Ich habe einen anderen verwirrenden Code. if let app = UIApplication.sharedApplication().delegate as? AppDelegate, let window = app.window {...}. Ist die 2. let auch optionale Bindung? Ich meine, appist nicht länger optional. richtig?
Honig
1
Es ist. appist nicht länger optional, aber seine windowEigenschaft ist (sein Typ ist UIWindow?), also ist es das, was Sie auspacken.
Nate Cook
7

Mit Swift 3 können Sie eine optionale Verkettung, eine switch-Anweisung oder ein optionales Muster verwenden, um Ihr Problem zu lösen.


1. Verwenden if let(optionales Binden / optionales Verketten)

Die Swift-Programmiersprache gibt Informationen zur optionalen Verkettung an:

Es können mehrere Abfragen miteinander verkettet werden, und die gesamte Kette schlägt ordnungsgemäß fehl, wenn ein Glied in der Kette Null ist.

Daher können Sie im einfachsten Fall das folgende Muster verwenden, um mehrere Abfragen in Ihrer optionalen Verkettungsoperation zu verwenden:

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. Verwenden von Tupeln und Wertebindung in einer switch-Anweisung

Als Alternative zu einer einfachen optionalen Verkettung kann die switch-Anweisung eine feinkörnige Lösung bieten, wenn sie mit Tupeln und Wertebindung verwendet wird:

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. Verwenden von Tupeln mit if case(optionales Muster)

if case( optionales Muster ) bietet eine bequeme Möglichkeit, die Werte der optionalen Aufzählung zu entpacken. Sie können es mit Tupeln verwenden, um eine optionale Verkettung mit mehreren Abfragen durchzuführen:

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
quelle
5

Swift 3.0

if let latitudeDouble = latitude as? Double, let longitudeDouble = longitude as? Double {
    // do stuff here
}
norbDEV
quelle
4
Sie sollten eine Änderung der akzeptierten Antwort vorschlagen und keine weitere Antwort mit geringerer Qualität hinzufügen.
jervine10