Verwenden Sie den Swift, wenn Sie den logischen AND-Operator && verwenden.

93

Wir wissen, dass wir eine if letAnweisung als Abkürzung verwenden können, um nach einer optionalen Null zu suchen und diese dann auszupacken.

Ich möchte dies jedoch mit einem anderen Ausdruck unter Verwendung des logischen AND-Operators kombinieren &&.

So mache ich hier zum Beispiel eine optionale Verkettung, um meinen rootViewController zu entpacken und optional auf tabBarController herunterzuspielen. Aber anstatt if-Anweisungen verschachtelt zu haben, möchte ich sie kombinieren.

if let tabBarController = window!.rootViewController as? UITabBarController {
    if tabBarController.viewControllers.count > 0 {
        println("do stuff")
     }
 }

Kombiniertes Geben:

if let tabBarController = window!.rootViewController as? UITabBarController &&
    tabBarController.viewControllers.count > 0 {
        println("do stuff")
     }
}

Das Obige gibt den Kompilierungsfehler an. Verwendung des nicht aufgelösten Bezeichners 'tabBarController'

Vereinfachung:

if let tabBarController = window!.rootViewController as? UITabBarController && true {
   println("do stuff")
}

Dies führt zu einem Kompilierungsfehler. Der gebundene Wert in einer bedingten Bindung muss vom optionalen Typ sein . Nachdem verschiedene syntaktische Variationen versucht wurden, gibt jede einen anderen Compilerfehler aus. Ich habe noch keine erfolgreiche Kombination aus Reihenfolge und Klammern gefunden.

Die Frage ist also, ist es möglich und wenn ja, welche Syntax ist richtig?

Beachten Sie, dass ich dies mit einer ifAnweisung tun möchte, nicht mit einer switchAnweisung oder einem ternären ?Operator.

Max MacLeod
quelle
Es ist immer eine gute Idee, die Fehlermeldungen in der Frage anzugeben.
Zaph
Einfachere Aussage für Leute, die gerne damit experimentieren:var foo : Int? = 10; if let bar = foo { if bar == 10 { println("Great success!") }}
DarkDust
Die Fehlermeldung bei der Verwendung if let bar = foo && bar == 10ist Use of unresolved identifier "bar"(auf der zweiten barnatürlich).
DarkDust
Nur eine Anmerkung, dass ich das obige Beispiel mit dem firstObject von Objective C wie folgt kürzen konnte: Wenn navigationController = tabBarController.viewControllers.bridgeToObjectiveC (). firstObject as? UINavigationController {
Max MacLeod
1
1. bridgeToObjectiveCist in Beta 5 verschwunden (und war möglicherweise nie für den allgemeinen Gebrauch gedacht). 2. Es gibt sowieso eine firstMethode für Swifts eingebauten ArrayTyp.
Rickster

Antworten:

143

Ab Swift 1.2 ist dies jetzt möglich . In den Beta-Versionshinweisen zu Swift 1.2 und Xcode 6.3 heißt es :

Leistungsstärkeres optionales Entpacken mit if let - Das if let-Konstrukt kann jetzt mehrere optionale Optionen gleichzeitig entpacken und dazwischenliegende boolesche Bedingungen einschließen. Auf diese Weise können Sie den bedingten Kontrollfluss ohne unnötige Verschachtelung ausdrücken.

Mit der obigen Aussage wäre die Syntax dann:

if let tabBarController = window!.rootViewController as? UITabBarController where tabBarController.viewControllers.count > 0 {
        println("do stuff")
}

Dies verwendet die whereKlausel.

Ein weiteres Beispiel, diesmal Casting AnyObjectzu Int, Auspacken der Option und Überprüfen, ob die ausgepackte Option die Bedingung erfüllt:

if let w = width as? Int where w < 500
{
    println("success!")
}

Für diejenigen, die jetzt Swift 3 verwenden, wurde "where" durch ein Komma ersetzt. Das Äquivalent wäre daher:

if let w = width as? Int, w < 500
{
    println("success!")
}
Max MacLeod
quelle
2
Dies sollte die gewählte Antwort sein.
Francis.Beauchamp
ja wie es jetzt geändert ist. Bryans Antwort war zu dieser Zeit richtig
Max MacLeod
58

In Swift 3 würde das Beispiel von Max MacLeod folgendermaßen aussehen:

if let tabBarController = window!.rootViewController as? UITabBarController, tabBarController.viewControllers.count > 0 {
    println("do stuff")
}

Das wherewurde ersetzt durch,

ph1lb4
quelle
10
Also, ist für && was gibt es für || ?
jeet.chanchawat
9
@ jeet.chanchawat logisch ODER macht in diesem Zusammenhang keinen Sinn. if letkann nur fortgesetzt werden, wenn die Option erfolgreich entpackt wurde und dem neuen Variablennamen zugewiesen ist. Wenn Sie sagten, OR <something else>dann könnten Sie leicht den ganzen Zweck des umgehen if let. Führen Sie für ein logisches ODER einfach einen normalen Vorgang durch ifund behandeln Sie innerhalb des Körpers die Tatsache, dass das erste Objekt zu diesem Zeitpunkt noch optional ist (nicht ausgepackt).
Jhabbott
37

Max 'Antwort ist richtig und eine Möglichkeit, dies zu tun. Beachten Sie jedoch, dass, wenn so geschrieben:

if let a = someOptional where someBool { }

Der someOptionalAusdruck wird zuerst aufgelöst. Wenn dies fehlschlägt, wird der someBoolAusdruck nicht ausgewertet (Kurzschlussauswertung, wie zu erwarten).

Wenn Sie dies umgekehrt schreiben möchten, können Sie dies folgendermaßen tun:

if someBool, let a = someOptional { }

In diesem Fall someBoolwird zuerst ausgewertet, und nur wenn er als wahr ausgewertet wird, wird der someOptionalAusdruck ausgewertet.

Par
quelle
5

Swift 4 werde ich verwenden,

let i = navigationController?.viewControllers.index(of: self)
if let index = i, index > 0, let parent = navigationController?.viewControllers[index-1] {
    // access parent
}
Sazzad Hissain Khan
quelle
4

Es ist nicht möglich.

Aus der schnellen Grammatik

GRAMMATIK EINER WENN ERKLÄRUNG

if-Anweisung → if -Bedingung Code-Block else-Klauselopt

if-Bedingung → Ausdruck | Erklärung

else-Klausel → else -Codeblock | sonst if-Anweisung

Der Wert einer Bedingung in einer if-Anweisung muss einen Typ haben, der dem BooleanType-Protokoll entspricht. Die Bedingung kann auch eine optionale Bindungsdeklaration sein, wie unter Optionale Bindung erläutert

if-Bedingung muss Ausdruck oder Deklaration sein. Sie können nicht sowohl Ausdruck als auch Deklaration haben.

let foo = barist eine Deklaration, die nicht zu einem Wert ausgewertet wird, der dem entspricht BooleanType. Es deklariert eine Konstante / Variable foo.

Ihre ursprüngliche Lösung ist gut genug, sie ist viel besser lesbar als die Kombination der Bedingungen.

Bryan Chen
quelle
aber sicher ist "if let" - was eine gültige Swift-Syntax ist - sowohl ein Ausdruck als auch eine Deklaration?
Max MacLeod
@MaxMacLeod let foo = barist Deklaration nicht Ausdruck. Sie können nicht tunlet boolValue = (let foo = bar)
Bryan Chen
OK, aber um den Swift-Leitfaden auf Seite 11 zu zitieren, lautet das Beispiel: if let name = optionalName. optionalName muss ein Ausdruck sein. Wenn optionalName kein optionaler Name ist, wird er als wahr ausgewertet. Der zweite Teil der Anweisung beginnt dann, wobei das ausgepackte optionale dem Namen zugewiesen wird. Die Frage ist also, ob "optionalName kein optionales" ein Ausdruck ist, der mit einem logischen UND erweitert werden kann. Übrigens denke ich, dass Sie wahrscheinlich insofern Recht haben, als es nicht möglich ist.
Max MacLeod
-1

Ich denke, Ihr ursprünglicher Vorschlag ist nicht schlecht. Eine (chaotischere) Alternative wäre:

if ((window!.rootViewController as? UITabBarController)?.viewControllers.count ?? 0) > 0 {
    println("do stuff")
}
jtbandes
quelle
1
aber Sie müssen Code, um tabBarControllerwieder zu besetzen
Bryan Chen