Utilisation du Swift si let avec l'opérateur AND logique &&

93

Nous savons que nous pouvons utiliser un if let instruction comme raccourci pour vérifier un nil facultatif, puis déballer.

Cependant, je veux combiner cela avec une autre expression utilisant l'opérateur logique AND &&.

Ainsi, par exemple, je fais ici un chaînage facultatif pour dérouler et éventuellement abaisser mon rootViewController vers tabBarController. Mais plutôt que d'avoir des instructions if imbriquées, j'aimerais les combiner.

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

Dons combinés:

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

Ce qui précède donne l'erreur de compilation Utilisation de l'identificateur non résolu 'tabBarController'

Simplifier:

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

Cela donne une erreur de compilation La valeur liée dans une liaison conditionnelle doit être de type facultatif . Après avoir tenté diverses variations syntaxiques, chacune donne une erreur de compilation différente. Je n'ai pas encore trouvé la combinaison gagnante d'ordre et de parenthèses.

Alors, la question est, est-ce possible et si oui quelle est la syntaxe correcte?

Notez que je veux faire cela avec une ifinstruction et non une switchinstruction ou un ?opérateur ternaire .

Max MacLeod
la source
Il est toujours judicieux de fournir les messages d'erreur dans la question.
zaph
var foo : Int? = 10; if let bar = foo { if bar == 10 { println("Great success!") }}
Déclaration
Le message d'erreur lors de l'utilisation if let bar = foo && bar == 10est Use of unresolved identifier "bar"(sur le second bar, bien sûr).
DarkDust
juste une note que j'ai pu raccourcir l'exemple ci-dessus en utilisant le firstObject d'Objective C comme suit: if let navigationController = tabBarController.viewControllers.bridgeToObjectiveC (). firstObject as? UINavigationController {
Max MacLeod
1
1. bridgeToObjectiveCest parti dans la bêta 5 (et n'a probablement jamais été destiné à un usage général). 2. Il existe de toute façon une firstméthode sur le type intégré de Swift Array.
rickster

Réponses:

143

Depuis Swift 1.2, c'est désormais possible . Les notes de version bêta de Swift 1.2 et Xcode 6.3 indiquent:

Déballage optionnel plus puissant avec if let - La construction if let peut désormais dérouler plusieurs options à la fois, ainsi qu'inclure des conditions booléennes intermédiaires. Cela vous permet d'exprimer un flux de contrôle conditionnel sans imbrication inutile.

Avec la déclaration ci-dessus, la syntaxe serait alors:

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

Cela utilise la whereclause.

Un autre exemple, cette fois-ci, transtyper AnyObjectvers Int, déballer l'option et vérifier que l'option non emballée remplit la condition:

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

Pour ceux qui utilisent maintenant Swift 3, "où" a été remplacé par une virgule. L'équivalent serait donc:

if let w = width as? Int, w < 500
{
    println("success!")
}
Max MacLeod
la source
2
Cela devrait être la réponse choisie.
Francis.Beauchamp
oui car c'est maintenant changé. La réponse de Bryan était correcte à ce moment
Max MacLeod
58

Dans l'exemple de Swift 3 Max MacLeod ressemblerait à ceci:

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

Le a whereété remplacé par,

ph1lb4
la source
10
Alors, c'est pour && qu'est-ce qu'il y a pour || ?
jeet.chanchawat
9
@ jeet.chanchawat OR logique n'a pas de sens dans ce contexte. if letne peut continuer que si l'option facultative a été déroulée avec succès et est affectée au nouveau nom de variable. Si vous l'avez dit, OR <something else>vous pourriez facilement contourner l'objectif général du if let. Pour un OU logique, faites simplement un normal ifet à l'intérieur du corps, gérez le fait que le premier objet est toujours optionnel à ce stade (non déballé).
jhabbott
37

La réponse de Max est correcte et constitue une façon de le faire. Notez cependant que lorsqu'il est écrit de cette façon:

if let a = someOptional where someBool { }

L' someOptionalexpression sera résolue en premier. En cas d'échec, lesomeBool expression ne sera pas évaluée (évaluation de court-circuit, comme vous vous en doutez).

Si vous voulez écrire ceci dans l'autre sens, vous pouvez le faire comme ceci:

if someBool, let a = someOptional { }

Dans ce cas, elle someBoolest évaluée en premier et ce n'est que si elle est évaluée à vrai que l' someOptionalexpression est évaluée.

par
la source
5

Swift 4 , je vais utiliser,

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

Ce n'est pas possible.

De la grammaire Swift

GRAMMAIRE D'UN ÉNONCÉ IF

if-statement → if si-condition code-block else-clauseopt

si-condition → expression | déclaration

clause else → bloc de code else | else instruction if

La valeur de toute condition dans une instruction if doit avoir un type conforme au protocole BooleanType. La condition peut également être une déclaration de liaison facultative, comme indiqué dans la liaison facultative

if-condition doit être une expression ou une déclaration. Vous ne pouvez pas avoir à la fois une expression et une déclaration.

let foo = barest une déclaration, elle n'évalue pas à une valeur conforme à BooleanType. Il déclare une constante / variable foo.

Votre solution originale est assez bonne, elle est beaucoup plus lisible que la combinaison des conditions.

Bryan Chen
la source
mais sûrement "if let" - qui est une syntaxe Swift valide - est à la fois une expression et une déclaration?
Max MacLeod
@MaxMacLeod let foo = barest une déclaration et non une expression. vous ne pouvez pas fairelet boolValue = (let foo = bar)
Bryan Chen
ok mais pour citer le guide Swift, page 11, l'exemple est: if let name = optionalName. optionalName doit être une expression dans laquelle si optionalName n'est pas un optionnel, il prend la valeur true. La deuxième partie de l'instruction démarre alors dans laquelle le facultatif déballé est assigné au nom. Donc, la question est, si "optionalName n'est pas un optionnel" est une expression, peut-il être développé avec un ET logique. Btw je pense que vous avez probablement raison en ce que cela ne peut pas être fait.
Max MacLeod
-1

Je pense que votre proposition initiale n'est pas trop mauvaise. Une alternative (plus désordonnée) serait:

if ((window!.rootViewController as? UITabBarController)?.viewControllers.count ?? 0) > 0 {
    println("do stuff")
}
jtbandes
la source
1
mais vous devez coder pour lancer à tabBarControllernouveau
Bryan Chen