what programming language guide functions for basics according swift swift2 control-flow convention

programming - swift variables



Swift: guardia vs si se deja (8)

He estado leyendo acerca de los opcionales en Swift, y he visto ejemplos en los que if let se usa para verificar si un Opcional tiene un valor, y en caso de que lo haga, haga algo con el valor sin envolver.

Sin embargo, he visto que en Swift 2.0 la guard palabras clave se usa principalmente. Me pregunto if let se ha eliminado de Swift 2.0 o si todavía se puede usar.

¿Debo cambiar mis programas que contienen if let guard ?


Guardia puede mejorar la claridad

Cuando usa guardia, tiene una expectativa mucho mayor de que el guardia tenga éxito y es algo importante que si no tiene éxito, entonces solo desea salir del alcance temprano . Al igual que guarda para ver si existe un archivo / imagen, si una matriz está vacía o no.

func icon() -> UIImage { guard let image = UIImage(named: "Photo") else { return UIImage(named: "Default")! //This is your fallback } return image //-----------------you''re always expecting/hoping this to happen }

Si escribe el código anterior con if-let, transmite al desarrollador de lectura que es más de un 50-50. Pero si usa guardia, agrega claridad a su código e implica que espero que funcione el 95% del tiempo ... si alguna vez falla, no sé por qué lo haría; es muy poco probable ... ¡pero luego use esta imagen predeterminada en su lugar o tal vez simplemente afirme con un mensaje significativo que describa lo que salió mal!

  • Evite los guard cuando crean efectos secundarios, los guardias deben usarse como un flujo natural . Evite los guardias cuando else cláusulas introducen efectos secundarios. Los guardias establecen las condiciones requeridas para que el código se ejecute correctamente, ofreciendo una salida anticipada

  • Cuando realiza un cálculo significativo en la rama positiva, refactorice desde if a una declaración de guard y devuelva el valor de recuperación en la cláusula else

Del libro de estilo rápido de Erica Sadun

Además, como resultado de las sugerencias anteriores y el código limpio, es más probable que desee / necesite agregar aserciones en las declaraciones de protección fallidas , solo mejora la legibilidad y deja en claro a otros desarrolladores lo que esperaba.

guard​ ​let​ image = ​UIImage​(named: selectedImageName) else { // YESSSSSS assertionFailure(​"Missing ​​/(​selectedImageName​)​​ asset"​) return } guard​ ​let​ image = ​UIImage​(named: selectedImageName) else { // NOOOOOOO ​  ​return }

De: Libro Swift Style de Erica Sadun + algunas modificaciones

(no utilizará afirmaciones / condiciones previas para if-let s. Simplemente no parece correcto)

Usar guardias también te ayuda a mejorar la claridad al evitar la pirámide de la fatalidad. Ver la respuesta de Nitin .

Guard crea una nueva variable

Hay una diferencia importante que creo que nadie ha explicado bien.

Sin embargo, ambos guard y if let desenvolver la variable

Con guard estás creando una nueva variable que existirá fuera de la instrucción else .

if let crear ninguna nueva variable, después de la instrucción else, solo ingresa el bloque de código si el opcional no es nulo. ¡La variable recién creada existe solo dentro del bloque de código, no después!

guard:

func someFunc(blog: String?) { guard let blogName = blog else { print("some ErrorMessage") print(blogName) // will create an error Because blogName isn''t defined yet return } print(blogName) // You can access it here ie AFTER the guard statement!! //And if I decided to do ''another'' guard let with the same name ie ''blogName'' then I would create an error! guard let blogName = blog else { // errorLine: Definition Conflicts with previous value. print(" Some errorMessage") return } print(blogName) }

if-let:

func someFunc(blog: String?) { if let blogName1 = blog { print(blogName1) // You can only access it inside the code block. Outside code block it doesn''t exist! } if let blogName1 = blog { // No Error at this line! Because blogName only exists inside the code block ie {} print(blogName1) } }

Para obtener más información sobre if let ver: ¿Por qué la redeclaración de enlace opcional no crea un error?

Guardia requiere salir del alcance

(También mencionado en la respuesta de Rob Napier):

DEBE tener un guard definido dentro de una función. Su propósito principal es abortar / devolver / salir del alcance, si no se cumple una condición:

var str : String? guard let blogName1 = str else { print("some error") return // Error: Return invalid outside of a func } print (blogName1)

Por if let te if let no necesitas tenerlo dentro de ninguna función:

var str : String? if let blogName1 = str { print(blogName1) // You don''t get any errors! }


Aprendí esto de Swift con Bob.

Si no típico

func checkDrinkingAge() { let canDrink = true if canDrink { print("You may enter") // More Code // More Code // More Code } else { // More Code // More Code // More Code print("Let me take you to the jail") } }

Problemas con Else-If

  1. Soportes anidados
  2. Tiene que leer cada línea para detectar el mensaje de error.

Declaración de protección Un bloque de protección solo se ejecuta si la condición es falsa, y saldrá de la función mediante retorno. Si la condición es verdadera, Swift ignora el bloqueo. Proporciona una salida anticipada y menos soportes.

func checkDrinkProgram() { let iCanDrink = true guard iCanDrink else { // if iCanDrink == false, run this block print("Let''s me take you to the jail") return } print("You may drink") // You may move on // Come on. // You may leave // You don''t need to read this. // Only one bracket on the bottom: feeling zen. }

Desenvuelva los opcionales con otra opción

Una declaración de protección no solo es útil para reemplazar un bloque condicional típico con una declaración else-if, sino que también es excelente para desenvolver opciones al minimizar el número de paréntesis. Para comparar, primero comencemos a desenvolver múltiples opcionales con else-if. Primero, creemos tres opciones que se desenvolverán.

var publicName: String? = "Bob Lee" var publicPhoto: String? = "Bob''s Face" var publicAge: Int? = nil

La peor pesadilla

func unwrapOneByOne() { if let name = publicName { if let photo = publicPhoto { if let age = publicAge { print("Bob: /(name), /(photo), /(age)") } else { print("age is mising") } } else { print("photo is missing") } } else { print("name is missing") } }

El código anterior ciertamente funciona pero viola el principio DRY. Es atroz. Vamos a desglosarlo. +

Ligeramente mejor El siguiente código es más legible que el anterior.

func unwrapBetter() { if let name = publicName { print("Yes name") } else { print("No name") return } if let photo = publicPhoto { print("Yes photo") } else { print("No photo") return } if let age = publicAge { print("Yes age") } else { print("No age") return } }

Desenvolver con guardia Las declaraciones else-if se pueden reemplazar con guardia.

func unwrapOneByOneWithGuard() { guard let name = publicName else { print("Name missing") return } guard let photo = publicPhoto else { print("Photo missing") return } guard let age = publicAge else { print("Age missing") return } print(name) print(photo) print(age) }

Desenvuelva múltiples opcionales con Else-If Hasta ahora, ha estado desenvolviendo opcionales uno por uno. Swift nos permite desenvolver múltiples opciones a la vez. Si uno de ellos contiene nil, ejecutará el bloque else.

func unwrap() { if let name = publicName, let photo = publicPhoto, let age = publicAge { print("Your name is /(name). I see your face right here, /(photo), you are /(age)") } else { // if any one of those is missing print("Something is missing") } }

Tenga en cuenta que cuando desenvuelve múltiples opciones a la vez, no puede identificar cuál contiene cero

Desenvolver múltiples opciones con Guardia Por supuesto, deberíamos usar guard sobre over-if. +

func unwrapWithGuard() { guard let name = publicName, let photo = publicPhoto, let age = publicAge else { // if one or two of the variables contain "nil" print("Something is missing") return } print("Your name is /(name). I see your, /(photo). You are /(age).") // Animation Logic // Networking // More Code, but still zen }


Cuándo usar if-let y cuándo usar guard es a menudo una cuestión de estilo.

Supongamos que tiene func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int y una matriz opcional de elementos ( var optionalArray: [SomeType]? ), Y necesita devolver 0 si la matriz es nil (no establecida ) o el count si la matriz tiene un valor (se establece).

Puede implementarlo de esta manera usando if-let :

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { if let array = optionalArray { return array.count } return 0 }

o así usando guard :

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { guard let array = optionalArray else { return 0 } return array.count }

Los ejemplos son funcionalmente idénticos.

Donde realmente brilla la guard es cuando tienes una tarea como validar datos, y quieres que la función falle temprano si algo está mal.

En lugar de anidar un montón de if-let s a medida que se acerca a finalizar la validación, la "ruta de éxito" y las opciones ahora vinculadas con éxito están en el alcance principal del método, porque las rutas de falla ya han regresado.


Diferencia básica

Guardia deja

  1. Proceso temprano existe desde el alcance
  2. Requerir puntaje existente como retorno, lanzamiento, etc.
  3. Cree una nueva variable a la que se pueda acceder desde el ámbito.

si deja

  1. No se puede acceder al alcance.
  2. No es necesario devolver la declaración. Pero podemos escribir

NOTA: Ambos se utilizan para desenvolver la variable Opcional.


La explicación más clara que vi fue en la Guía de estilo Github Swift :

if agrega un nivel de profundidad:

if n.isNumber { // Use n here } else { return }

guard no:

guard n.isNumber else { return } // Use n here


Trataré de explicar la utilidad de las declaraciones de guardia con algún código (no optimizado).

Tiene una interfaz de usuario donde está validando campos de texto para el registro de usuarios con nombre, apellido, correo electrónico, teléfono y contraseña.

Si algún textField no contiene texto válido, debe hacer que ese campo sea FirstResponder.

Aquí está el código no optimizado:

//pyramid of doom func validateFieldsAndContinueRegistration() { if let firstNameString = firstName.text where firstNameString.characters.count > 0{ if let lastNameString = lastName.text where lastNameString.characters.count > 0{ if let emailString = email.text where emailString.characters.count > 3 && emailString.containsString("@") && emailString.containsString(".") { if let passwordString = password.text where passwordString.characters.count > 7{ // all text fields have valid text let accountModel = AccountModel() accountModel.firstName = firstNameString accountModel.lastName = lastNameString accountModel.email = emailString accountModel.password = passwordString APIHandler.sharedInstance.registerUser(accountModel) } else { password.becomeFirstResponder() } } else { email.becomeFirstResponder() } } else { lastName.becomeFirstResponder() } } else { firstName.becomeFirstResponder() } }

Puede ver arriba, que todas las cadenas (firstNameString, lastNameString, etc.) solo son accesibles dentro del alcance de la instrucción if. por lo que crea esta "pirámide de la fatalidad" y tiene muchos problemas, incluida la legibilidad y la facilidad para mover las cosas (si se altera el orden de los campos, debe reescribir la mayor parte de este código)

Con la declaración de protección (en el código a continuación), puede ver que estas cadenas están disponibles fuera de {} y se utilizan, si todos los campos son válidos.

// guard let no pyramid of doom func validateFieldsAndContinueRegistration() { guard let firstNameString = firstName.text where firstNameString.characters.count > 0 else { firstName.becomeFirstResponder() return } guard let lastNameString = lastName.text where lastNameString.characters.count > 0 else { lastName.becomeFirstResponder() return } guard let emailString = email.text where emailString.characters.count > 3 && emailString.containsString("@") && emailString.containsString(".") else { email.becomeFirstResponder() return } guard let passwordString = password.text where passwordString.characters.count > 7 else { password.becomeFirstResponder() return } // all text fields have valid text let accountModel = AccountModel() accountModel.firstName = firstNameString accountModel.lastName = lastNameString accountModel.email = emailString accountModel.password = passwordString APIHandler.sharedInstance.registerUser(accountModel) }

Si cambia el orden de los campos, simplemente mueva las líneas de código respectivas hacia arriba o hacia abajo, y estará listo para comenzar.

Esta es una explicación muy simple y un caso de uso. ¡Espero que esto ayude!


Guard

  • Se utiliza una declaración de guardia para transferir el control del programa fuera de un alcance si no se cumplen una o más condiciones.

  • El valor de cualquier condición en una declaración de protección debe ser de tipo Bool o un tipo puenteado a Bool. La condición también puede ser una declaración vinculante opcional

Una declaración de guardia tiene la siguiente forma:

guard condition else { //Generally return }

si deja

if let roomCount = optionalValue { print("roomCount available") } else { print("roomCount is nil") }


if let and guard let sirve para propósitos similares pero distintos.

El caso de guard "else" debe salir del alcance actual. En general, eso significa que debe llamar a return o abortar el programa. guard se usa para proporcionar un retorno temprano sin requerir el anidamiento del resto de la función.

if let anidar su alcance, y no requiere nada especial de él. Puede return o no.

En general, si el bloque if-let iba a ser el resto de la función, o su cláusula else tendría un return o un aborto, entonces debería usar guard lugar. Esto a menudo significa (al menos en mi experiencia), en caso de duda, la guard es la mejor respuesta. Pero hay muchas situaciones en las que if let todavía es apropiado.