Je lisais des articles sur Optionals dans Swift, et j’ai vu des exemples où if let
est utilisé pour vérifier si un facultatif contient une valeur et, le cas échéant, effectue quelque chose avec la valeur non enveloppée.
Cependant, j'ai vu que dans Swift 2.0, le mot clé guard
est principalement utilisé. Je me demande si if let
a été supprimé de Swift 2.0 ou s’il est encore possible de l’utiliser.
Devrais-je changer mes programmes contenant if let
à guard
?
if let
et guard let
servent des buts similaires, mais distincts.
Le cas "else" de guard
doit quitter la portée actuelle. Généralement, cela signifie qu’il doit appeler return
ou abandonner le programme. guard
est utilisé pour fournir un retour rapide sans nécessiter d'imbrication du reste de la fonction.
if let
_ nids sa portée, et n'exige rien de spécial. Il peut return
ou non.
En général, si le if-let
bloque serait le reste de la fonction, ou sa clause else
aurait un return
ou serait abandonnée, vous devriez alors utiliser guard
. Cela signifie souvent (du moins selon mon expérience) qu'en cas de doute, guard
est généralement la meilleure réponse. Mais il y a beaucoup de situations où if let
est toujours approprié.
Lorsque vous utilisez la garde, vous attendez beaucoup plus haut pour la garde réussir et il est assez important que si pas réussi, alors vous voulez juste quitter scope early. Comme si vous gardiez pour voir si un fichier/image existe, si un tableau est vide ou non.
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 vous écrivez le code ci-dessus avec if-let, cela indique au développeur que c'est plus un 50-50. Mais si vous utilisez guard, vous ajoutez clarté à votre code et cela implique que cela fonctionne 95% du temps ... si cela échoue, je ne sais pas pourquoi; c'est très peu probable ... mais alors utilisez simplement cette image par défaut à la place ou peut-être simplement assert avec un message explicite décrivant ce qui s'est mal passé!
Evitez
guard
s quand ils créent des effets secondaires, les gardes doivent être utilisés comme un flux naturel . Évitez les gardes quand les clauseselse
introduisent des effets secondaires. Les gardes établissent les conditions requises pour que le code s'exécute correctement, offrant une sortie anticipéeLorsque vous effectuez un calcul significatif dans la branche positive, refactorez
if
en une instructionguard
et renvoie la valeur de repli dans la clauseelse
De plus, à la suite des suggestions ci-dessus et du code épuré, c'est plus probable vous voudrez/aurez besoin d'ajouter des assertions dans échoué des instructions de protection, cela améliore simplement la lisibilité et indique clairement aux autres développeurs ce à quoi vous vous attendiez.
guard let image = UIImage(named: selectedImageName) else { // YESSSSSS assertionFailure("Missing \(selectedImageName) asset") return } guard let image = UIImage(named: selectedImageName) else { // NOOOOOOO return }
De: d'Erica Sadun Swift Livre de styles + quelques modifications
(vous n'utiliserez pas d'assert/preconditions pour if-let
s. Ça ne semble pas juste)
L'utilisation de gardes vous aide également à améliorer la clarté de en évitant la pyramide de Doom. Voir la réponse de Nitin .
Il y a une différence importante que je crois que personne n'a bien expliqué.
guard
et if let
dérouler la variable cependant
Avec guard
, vous créez une nouvelle variable qui existera en dehors de else
déclaration.
Avec if let
_ vous ne créez pas de nouvelle variable - après l'instruction else, vous ne faites que entrer le bloc de code = si l'option est non-nulle. La nouvelle variable créée n'existe que à l'intérieur du code bloqué pas aprè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)
}
}
Pour plus d'informations sur if let
voir: Pourquoi la redéclaration de liaison facultative ne crée pas d'erreur
(Également mentionné dans la réponse de Rob Napier):
Vous DEVEZ avoir guard
défini à l'intérieur une fonction. Son but principal est d’avorter/retourner/sortir de la portée, si une condition n’est pas remplie:
var str : String?
guard let blogName1 = str else {
print("some error")
return // Error: Return invalid outside of a func
}
print (blogName1)
Pour if let
vous n’avez pas besoin de l’avoir dans une fonction quelconque:
var str : String?
if let blogName1 = str {
print(blogName1) // You don't get any errors!
}
Quand utiliser if-let
Et quand utiliser guard
est souvent une question de style.
Supposons que vous avez func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
et un tableau optionnel d'éléments (var optionalArray: [SomeType]?
), Et que vous devez renvoyer soit 0
Si le tableau est nil
(non- set) ou count
si le tableau a une valeur (est définie).
Vous pouvez l'implémenter comme ceci en utilisant if-let
:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
if let array = optionalArray {
return array.count
}
return 0
}
ou comme ceci en utilisant guard
:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
guard let array = optionalArray else {
return 0
}
return array.count
}
Les exemples sont fonctionnellement identiques.
Où guard
brille vraiment, c’est lorsque vous avez une tâche comme la validation des données et que vous souhaitez que la fonction échoue rapidement si quelque chose ne va pas.
Au lieu d'imbriquer un groupe de if-let
Lorsque vous vous approchez de la fin de la validation, le "chemin de réussite" et les options optionnelles désormais liées avec succès sont tous dans la portée principale de la méthode, car les chemins d'échec ont déjà été renvoyés. .
Je vais essayer d'expliquer l'utilité des déclarations de garde avec du code (non optimisé).
Vous avez une interface utilisateur dans laquelle vous validez les champs de texte pour l'enregistrement de l'utilisateur avec le nom, le nom, l'adresse email, le téléphone et le mot de passe.
Si un objet textField ne contient pas de texte valide, il convient que ce champ devienne firstResponder.
voici le code non optimisé:
//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()
}
}
Vous pouvez voir ci-dessus que toutes les chaînes (firstNameString, lastNameString, etc.) ne sont accessibles que dans la portée de l'instruction if. il crée donc cette "pyramide de Doom" et pose de nombreux problèmes, notamment de lisibilité et de facilité de déplacement (si l'ordre des champs est modifié, vous devez réécrire l'essentiel de ce code).
Avec l'instruction guard (dans le code ci-dessous), vous pouvez voir que ces chaînes sont disponibles en dehors de la chaîne {}
et sont utilisés si tous les champs sont valides.
// 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 l'ordre des champs change, déplacez simplement les lignes de code respectives vers le haut ou le bas et vous êtes prêt à partir.
Ceci est une explication très simple et un cas d'utilisation. J'espère que cela t'aides!
Différence de base
Remarque: les deux sont utilisés pour déballer la variable facultative.
L'explication la plus claire que j'ai vue se trouvait dans le Github Swift Style Guide) :
if
ajoute un niveau de profondeur:
if n.isNumber {
// Use n here
} else {
return
}
guard
ne:
guard n.isNumber else {
return
}
// Use n here
Une instruction de protection est utilisée pour transférer le contrôle de programme hors d’une portée si une ou plusieurs conditions ne sont pas remplies.
La valeur d'une condition dans une instruction guard doit être de type Bool ou d'un type ponté en Bool. La condition peut aussi être une déclaration obligatoire
Une déclaration de garde a la forme suivante:
guard condition else {
//Generally return
}
- Aussi populaire que reliure optionnelle
- Pour accéder à un objet optionnel, nous utilisons si let
if let roomCount = optionalValue {
print("roomCount available")
} else {
print("roomCount is nil")
}
J'ai appris cela de Swift avec Bob ..
Typique Else-If
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")
}
}
Problèmes avec Else-If
Guard Statement Un bloc de garde ne fonctionne que si la condition est fausse et il sortira de la fonction par le retour. Si la condition est vraie, Swift ignore le bloc de garde. Il fournit une sortie rapide et moins de crochets. +
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.
}
Déballez les options avec Else-If
Une instruction de protection est non seulement utile pour remplacer un bloc conditionnel typique par une instruction else-if, mais également très utile pour décompresser des options en minimisant le nombre de crochets. Pour comparer, commençons par comment décompresser plusieurs options avec else-if. Tout d’abord, créons trois options qui seront déballées.
var publicName: String? = "Bob Lee"
var publicPhoto: String? = "Bob's Face"
var publicAge: Int? = nil
Le pire cauchemar
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")
}
}
Le code ci-dessus fonctionne certainement mais viole le principe DRY. C'est atroce. Décomposons-le. +
légèrement mieux Le code ci-dessous est plus lisible que ci-dessus. +
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
}
}
Déballer avec Guard Les instructions else-if peuvent être remplacées par Guard. +
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)
}
Déballer plusieurs options avec Else-If Jusqu'à présent, vous avez décompressé les options une par une. Swift nous permet de décompresser plusieurs options en même temps. Si l'une d'elles contient la valeur nil, elle exécutera le bloc 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")
}
}
Sachez que lorsque vous déballez plusieurs options à la fois, vous ne pouvez pas identifier celles qui contiennent zéro
Déballez plusieurs options avec Guard Bien sûr, nous devrions utiliser la protection par-dessus-sinon. +
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
}