Usar Swift si se permite con el operador AND lógico &&

93

Sabemos que podemos usar una if letdeclaración como una abreviatura para verificar un nulo opcional y luego desenvolverlo.

Sin embargo, quiero combinar eso con otra expresión usando el operador lógico AND &&.

Entonces, por ejemplo, aquí hago un encadenamiento opcional para desenvolver y, opcionalmente, bajar mi rootViewController a tabBarController. Pero en lugar de anidar declaraciones if, me gustaría combinarlas.

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

Donaciones combinadas:

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

Lo anterior da el error de compilación Uso del identificador no resuelto 'tabBarController'

Simplificando:

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

Esto da un error de compilación. El valor enlazado en un enlace condicional debe ser de tipo opcional . Después de haber intentado varias variaciones sintácticas, cada una da un error de compilación diferente. Todavía tengo que encontrar la combinación ganadora de orden y paréntesis.

Entonces, la pregunta es, ¿es posible y, de ser así, cuál es la sintaxis correcta?

Tenga en cuenta que quiero hacer esto con una ifdeclaración, no una switchdeclaración o un ?operador ternario .

Max MacLeod
fuente
Siempre es una buena idea proporcionar los mensajes de error en la pregunta.
zaph
Declaración más simple para las personas a las que les gusta experimentar con esto:var foo : Int? = 10; if let bar = foo { if bar == 10 { println("Great success!") }}
DarkDust
El mensaje de error al usar if let bar = foo && bar == 10es Use of unresolved identifier "bar"(en el segundo bar, por supuesto).
DarkDust
solo una nota de que pude acortar el ejemplo anterior usando firstObject de Objective C de la siguiente manera: si deja navigationController = tabBarController.viewControllers.bridgeToObjectiveC (). firstObject as? UINavigationController {
Max MacLeod
1
1. ya no bridgeToObjectiveCestá en la versión beta 5 (y posiblemente nunca fue diseñado para uso general). 2. De todos modos, existe un firstmétodo en el tipo integrado de Swift Array.
rickster

Respuestas:

143

A partir de Swift 1.2, esto ahora es posible . Las notas de la versión beta de Swift 1.2 y Xcode 6.3 indican:

Desenvase opcional más potente con if let: la construcción if let ahora puede desenvolver múltiples opcionales a la vez, así como también incluir condiciones booleanas intermedias. Esto le permite expresar un flujo de control condicional sin anidamientos innecesarios.

Con la declaración anterior, la sintaxis sería:

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

Esto usa la wherecláusula.

Otro ejemplo, esta vez lanzando AnyObjecta Int, desenvolviendo el opcional y verificando que el opcional desenvuelto cumpla con la condición:

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

Para aquellos que ahora usan Swift 3, "donde" ha sido reemplazado por una coma. Por tanto, el equivalente sería:

if let w = width as? Int, w < 500
{
    println("success!")
}
Max MacLeod
fuente
2
Esta debería ser la respuesta elegida.
Francis.Beauchamp
sí, ya que ahora ha cambiado. La respuesta de Bryan fue correcta en ese momento
Max MacLeod
58

En Swift 3, el ejemplo de Max MacLeod se vería así:

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

El wherefue reemplazado por,

ph1lb4
fuente
10
Entonces, es para && para qué hay || ?
jeet.chanchawat
9
@ jeet.chanchawat OR lógico no tiene sentido en este contexto. if letsólo puede continuar si la opción opcional se desenvuelve correctamente y se asigna al nuevo nombre de variable. Si lo dijeras OR <something else>, podrías omitir fácilmente todo el propósito del if let. Para OR lógico, simplemente haga un iftrato normal y dentro del cuerpo con el hecho de que el primer objeto todavía es opcional en ese punto (no desenvuelto).
jhabbott
37

La respuesta de Max es correcta y una forma de hacerlo. Sin embargo, tenga en cuenta que cuando se escribe de esta manera:

if let a = someOptional where someBool { }

La someOptionalexpresión se resolverá primero. Si falla, la someBoolexpresión no se evaluará (evaluación de cortocircuito, como era de esperar).

Si desea escribir esto al revés, puede hacerlo así:

if someBool, let a = someOptional { }

En este caso someBoolse evalúa primero, y solo si se evalúa como verdadero se someOptionalevalúa la expresión.

par
fuente
5

Swift 4 , lo usaré,

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

No es posible.

De Swift grammar

GRAMÁTICA DE UNA DECLARACIÓN IF

sentencia if → si code-block-si-condición else clauseopt

condición-if → expresión | declaración

cláusula-else → bloque de código else | más si-declaración

El valor de cualquier condición en una instrucción if debe tener un tipo que se ajuste al protocolo BooleanType. La condición también puede ser una declaración vinculante opcional, como se explica en Vinculación opcional

if-condition debe ser expresión o declaración. No puedes tener tanto expresión como declaración.

let foo = bares una declaración, no se evalúa a un valor que se ajuste a BooleanType. Declara una constante / variable foo.

Su solución original es lo suficientemente buena, es mucho más legible que combinando las condiciones.

Bryan Chen
fuente
pero seguramente "if let", que es una sintaxis Swift válida, ¿es tanto una expresión como una declaración?
Max MacLeod
@MaxMacLeod let foo = bares una declaración, no una expresión. no se puede hacerlet boolValue = (let foo = bar)
Bryan Chen
ok, pero para citar la guía Swift, página 11, el ejemplo es: if let name = optionalName. optionName debe ser una expresión por la cual si optionalName no es opcional, se evalúa como verdadero. La segunda parte de la declaración entra en acción mediante la cual el opcional sin envolver se asigna a name. Entonces, la pregunta es, si "OptionalName no es opcional" es una expresión, ¿se puede expandir con un AND lógico? Por cierto, creo que probablemente tengas razón en que no se puede hacer.
Max MacLeod
-1

Creo que tu propuesta original no es tan mala. Una alternativa (más complicada) sería:

if ((window!.rootViewController as? UITabBarController)?.viewControllers.count ?? 0) > 0 {
    println("do stuff")
}
jtbandes
fuente
1
pero necesitas codificar para lanzar de tabBarControllernuevo
Bryan Chen