web-dev-qa-db-fra.com

Mot clé de la garde de Swift

Swift 2 a introduit le mot-clé guard, qui pourrait être utilisé pour s'assurer que diverses données sont prêtes à être configurées. Un exemple que j'ai vu sur ce site Web illustre une fonction submitTapped:

func submitTapped() {
    guard username.text.characters.count > 0 else {
        return
    }

    print("All good")
}

Je me demande si l'utilisation de guard diffère de la manière habituelle, en utilisant une condition if. Donne-t-il des avantages que vous ne pourriez pas obtenir en utilisant un simple chèque?

189
David Snabel

Lecture cet article J'ai constaté de grands avantages avec Guard

Ici, vous pouvez comparer l’utilisation de guard avec un exemple:

C'est la partie sans garde:

func fooBinding(x: Int?) {
    if let x = x where x > 0 {
        // Do stuff with x
        x.description
    }

    // Value requirements not met, do something
}
  1. Ici, vous mettez le code désiré dans toutes les conditions

    Cela ne vous pose peut-être pas immédiatement un problème, mais vous pouvez imaginer à quel point cela pourrait devenir confus s'il était imbriqué dans de nombreuses conditions qui devaient toutes être remplies avant d'exécuter vos déclarations.

La meilleure façon de résoudre ce problème consiste à effectuer chacune de vos vérifications en premier, puis à quitter si aucune n’est remplie. Cela permet de comprendre facilement quelles conditions feront quitter cette fonction.

Mais maintenant, nous pouvons utiliser la garde et nous pouvons voir qu'il est possible de résoudre certains problèmes:

func fooGuard(x: Int?) {
    guard let x = x where x > 0 else {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
    x.description
}
  1. Vérifier la condition que vous voulez, pas celle que vous ne voulez pas. Ceci est similaire à une affirmation. Si la condition n’est pas remplie, l’instruction else de guard est exécutée et sort de la fonction.
  2. Si la condition est satisfaite, la variable facultative est décompressée automatiquement pour vous dans la portée de l'appel de l'instruction Guard - dans ce cas, la fonction fooGuard (_ :).
  3. Vous vérifiez les mauvaises affaires à un stade précoce, ce qui rend votre fonction plus lisible et plus facile à gérer.

Ce même schéma s'applique également aux valeurs non facultatives:

func fooNonOptionalGood(x: Int) {
    guard x > 0 else {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
}

func fooNonOptionalBad(x: Int) {
    if x <= 0 {
        // Value requirements not met, do something
        return
    }

    // Do stuff with x
}

Si vous avez encore des questions, vous pouvez lire l’intégralité de l’article: Déclaration de garde rapide.

Conclusion

Et enfin, en lisant et en testant, j’ai trouvé que si vous utilisiez la garde pour déballer les options,

ces valeurs non enveloppées restent pour que vous les utilisiez dans le reste de votre bloc de code

.

guard let unwrappedName = userName else {
    return
}

print("Your username is \(unwrappedName)")

Ici, la valeur non emballée ne serait disponible que dans le bloc if

if let unwrappedName = userName {
    print("Your username is \(unwrappedName)")
} else {
    return
}

// this won't work – unwrappedName doesn't exist here!
print("Your username is \(unwrappedName)")
359
Jorge Casariego

Contrairement à if, guard crée la variable accessible de l'extérieur du bloc. Il est utile de déballer beaucoup de Optionals.

35
takebayashi

Il y a vraiment deux gros avantages à guard. L’une consiste à éviter la pyramide de Doom, comme d’autres l'ont déjà mentionné - de nombreuses déclarations if let agaçantes imbriquées l'une dans l'autre se déplaçant de plus en plus à droite.

L’autre avantage est souvent que la logique que vous souhaitez implémenter est plus "if not let" que "if let { } else".

Voici un exemple: supposons que vous souhaitiez implémenter accumulate - un croisement entre map et reduce où il vous restitue un tableau de en cours d’exécution. La voici avec guard:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {
        // if there are no elements, I just want to bail out and
        // return an empty array
        guard var running = self.first else { return [] }

        // running will now be an unwrapped non-optional
        var result = [running]

        // dropFirst is safe because the collection
        // must have at least one element at this point
        for x in dropFirst(self) {
            running = combine(running, x)
            result.append(running)
        }
        return result
    }

}


let a = [1,2,3].accumulate(+)  // [1,3,6]
let b = [Int]().accumulate(+)  // []

Comment l'écririez-vous sans garde, mais en utilisant toujours first qui renvoie une valeur facultative? Quelque chose comme ça:

extension Sliceable where SubSlice.Generator.Element == Generator.Element {

    func accumulate(combine: (Generator.Element,Generator.Element)->Generator.Element) -> [Generator.Element] {

        if var running = self.first  {
            var result = [running]

            for x in dropFirst(self) {
                running = combine(running, x)
                result.append(running)
            }
            return result
        }
        else {
            return []
        }
    }

}

L’imbrication supplémentaire est gênante, mais il n’est pas aussi logique d’avoir la if et la else aussi éloignées les unes des autres. C’est beaucoup plus lisible d’avoir la sortie anticipée pour le cas vide, puis de continuer avec le reste de la fonction comme si cela n’était pas possible.

23
Airspeed Velocity

Lorsqu'une condition est remplie avec guard, elle expose les variables déclarées dans le bloc guard au reste du bloc de code, en les mettant dans son champ d'application. Comme indiqué précédemment, ce qui sera certainement utile avec les instructions imbriquées if let.

Notez que la garde nécessite un retour ou un lancer dans sa déclaration else.

Analyser JSON avec Guard

Vous trouverez ci-dessous un exemple d'analyse syntaxique d'un objet JSON à l'aide de guard plutôt que de if-let. Ceci est un extrait d'une entrée de blog qui inclut un fichier de terrain de jeu que vous pouvez trouver ici:

Comment utiliser Guard dans Swift 2 pour analyser JSON

func parseJSONWithGuard(data : [String : AnyObject]) throws -> Developer {

    guard let firstname = data["First"] as? String  else {
        return Developer() // we could return a nil Developer()
    }

    guard let lastname = data["Last"] as? String else {
        throw ParseError.BadName // or we could throw a custom exception and handle the error
    }

    guard let website = data["WebSite"] as? String else {
        throw ParseError.BadName
    }

    guard let iosDev = data["iosDeveloper"] as? Bool else {
        throw ParseError.BadName
    }



    return Developer(first: firstname, last: lastname, site: website, ios: iosDev)

}

télécharger l'aire de jeu: aire de jeu de la garde

Plus d'informations:

Voici un extrait du Le Swift Guide du langage de programmation:

Si la condition de l'instruction Guard est remplie, l'exécution du code se poursuit après l'accolade fermante de l'instruction Guard. Toutes les variables ou constantes auxquelles des valeurs ont été affectées à l'aide d'une liaison facultative en tant que partie de la condition sont disponibles pour le reste du bloc de code dans lequel l'instruction Guard apparaît.

Si cette condition n'est pas remplie, le code à l'intérieur de la branche else est exécuté. Cette branche doit transférer le contrôle pour quitter le bloc de code dans lequel cette instruction de protection apparaît. Elle peut le faire avec une instruction de transfert de contrôle telle que return, break ou continue, ou elle peut appeler une fonction ou une méthode qui ne renvoie pas, telle que comme fatalError ().

19
Dan Beaulieu

L'un des avantages est l'élimination de nombreuses instructions if let imbriquées. Voir la vidéo "Quoi de neuf dans Swift" de la WWDC aux alentours de 15h30, dans la section intitulée "Pyramid of Doom".

7
zaph

Déclaration de garde va faire. c'est un couple de différent

1) il me permet de réduire imbriqué si déclaration
2) c’est augmenter ma portée que ma variable accessible

si déclaration

func doTatal(num1 : Int?, num2: Int?) {
  // nested if statement
    if let fistNum = num1 where num1 > 0 {
        if let lastNum = num2 where num2 < 50 {

          let total = fistNum + lastNum
        }
    }
 // don't allow me to access out of the scope 
 //total = fistNum + lastNum 
}

déclaration de garde

func doTatal(num1 : Int?, num2: Int?) {
   //reduce  nested if statement and check positive way not negative way 
    guard let fistNum = num1 where num1 > 0 else{
      return
    }
    guard  let lastNum = num2 where num2 < 50 else {
     return
    }
    // increase my scope which my variable accessible
    let total = fistNum + lastNum

}
5
Nazmul Hasan

Quand utiliser les gardes

Si vous avez un contrôleur de vue avec quelques éléments UITextField ou un autre type d’entrée utilisateur, vous remarquerez immédiatement que vous devez déballer textField.text en option pour obtenir le texte à l’intérieur (le cas échéant!). isEmpty ne vous fera aucun bien ici, sans aucune entrée, le champ de texte retournera simplement nil.

Vous en avez donc quelques-uns que vous décompressez et que vous transmettez éventuellement à une fonction qui les publie sur un noeud final de serveur. Nous ne souhaitons pas que le code de serveur traite des valeurs nulles ou envoie par erreur des valeurs non valides au serveur. Nous allons donc déballer ces valeurs d'entrée avec guard.

func submit() {
    guard let name = nameField.text else {
        show("No name to submit")
        return
    }

    guard let address = addressField.text else {
        show("No address to submit")
        return
    }

    guard let phone = phoneField.text else {
        show("No phone to submit")
        return
    }

    sendToServer(name, address: address, phone: phone)
}

func sendToServer(name: String, address: String, phone: String) {
  ...
}

Vous remarquerez que notre fonction de communication avec le serveur prend des valeurs de chaîne non facultatives en tant que paramètres, d’où le déploiement préalable de la protection. Le décompactage est un peu peu intuitif car nous sommes habitués à décompresser avec if, qui permet de décompresser les valeurs à utiliser dans un bloc. Ici, la déclaration de garde a un bloc associé mais c’est en réalité un bloc d’autre - c’est-à-dire ce que vous faites si le décompression échoue - les valeurs sont décompressées directement dans le même contexte que la déclaration elle-même.

// séparation des préoccupations

Sans garde

Sans garde, nous nous retrouverions avec un gros tas de code qui ressemblerait à une pyramide de Doom . Cela ne convient pas à l’ajout de nouveaux champs à notre formulaire ni à un code très lisible. Il peut être difficile de suivre l’indentation, en particulier avec tant d’autres déclarations à chaque branche.

func nonguardSubmit() {
    if let name = nameField.text {
        if let address = addressField.text {
            if let phone = phoneField.text {
                sendToServer(name, address: address, phone: phone)
            } else {
                show("no phone to submit")
            }
        } else {
            show("no address to submit")
        }
    } else {
        show("no name to submit")
    }
}

Oui, nous pourrions même combiner toutes ces instructions if si let en une seule instruction séparée par des virgules, mais nous perdrions la possibilité de déterminer laquelle avait échoué et de présenter un message à l'utilisateur.

https://thatthinginswift.com/guard-statement-Swift/

5
Honey

En utilisant garde notre intension est claire. nous ne voulons pas exécuter le reste du code si cette condition particulière n'est pas remplie. Ici, nous pouvons aussi rallonger la chaîne, veuillez regarder le code ci-dessous:

guard let value1 = number1, let value2 = number2 else { return }
 // do stuff here
5
Narendra G

De la documentation Apple:

Déclaration de garde

Une instruction guard 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.

Synatx:

guard condition else {
    statements
}

Avantage:

1. En utilisant l'instruction guard, nous pouvons nous débarrasser des conditionnels profondément imbriqués dont le seul but est de valider un ensemble d'exigences.

2. Il a été conçu spécifiquement pour quitter une méthode ou une fonction tôt.

si vous utilisez si let ci-dessous est le code à quoi il ressemble.

  let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

        if error == nil {
            if let  statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 {
                if let data = data {

                    //Process Data Here.
                    print("Data: \(data)")

                } else {
                    print("No data was returned by the request!")
                }
            } else {
                print("Your request returned a status code other than 2XX!")
            }
        } else {
            print("Error Info: \(error.debugDescription)")
        }
    }
    task.resume()

À l'aide de guard, vous pouvez transférer le contrôle hors du domaine d'application si une ou plusieurs conditions ne sont pas remplies.

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in

            /* GUARD: was there an error? */
            guard (error == nil) else {
                print("There was an error with your request: \(error)")
                return
            }

            /* GUARD: Did we get a successful 2XX response? */
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, statusCode >= 200 && statusCode <= 299 else {
                print("Your request returned a status code other than 2XX!")
                return
            }

            /* GUARD: was there any data returned? */
            guard let data = data else {
                print("No data was returned by the request!")
                return
            }

            //Process Data Here.
            print("Data: \(data)")
}
task.resume()

Référence:

1. Swift 2: Quitter tôt avec garde 2. dacity 3. Déclaration de la garde

3
Ashok R

Comme une instruction if, guard exécute des instructions en fonction de la valeur booléenne d'une expression. Contrairement à une instruction if, les instructions de garde ne sont exécutées que si les conditions ne sont pas remplies. Vous pouvez penser à la garde plutôt à une assertion, mais plutôt que de vous écraser, vous pouvez quitter avec élégance.

se référer à: http://ericcerney.com/Swift-guard-statement/

2
Zgpeace

En termes simples, il fournit un moyen de valider les champs avant leur exécution. C'est un bon style de programmation car il améliore la lisibilité. Dans d'autres langues, cela peut ressembler à ceci:

func doSomething() {
    if something == nil {
        // return, break, throw error, etc.
    }
    ...
}

Mais parce que Swift vous fournit des options, nous ne pouvons pas vérifier si c'est nul et affecter sa valeur à une variable. En revanche, if let vérifie que c'est pas nil et affecte une variable pour conserver la valeur réelle. C'est ici que guard entre en jeu. Cela vous donne un moyen plus concis de sortir plus tôt en utilisant des options.

1
gunby

Cela rend vraiment le flux d'une séquence avec plusieurs recherches et options optionnelles beaucoup plus concis et clair et réduit considérablement les possibilités d'imbrication. Voir le post d'Erica Sadun pour remplacer Ifs . .... Pourrait s'emporter, un exemple ci-dessous:

    let filteredLinks = locationsLinkedToList.filter({$0.actionVerb == movementCommand})
    guard let foundLink = filteredLinks.first else {return ("<Person> cannot go in that direction.", nil, nil)}
    guard filteredLinks.count == 1 else {return ("<Person> cannot decide which route to take.", nil, nil)}
    guard let nextLocation = foundLink.toLocation else {return ("<Person> cannot go in that direction.", nil, nil)}

Voyez si ça colle.

1
DavidS

Source: https://thenucleargeeks.com/2019/05/09/guard-in-Swift/

Voyons l'exemple pour bien le comprendre

Exemple 1:

func validate() {         
    guard 3>2 else {             
    print ("False")             
    return         
    }         
    print ("True") //True     
} 
validate()

Dans l'exemple ci-dessus, nous voyons que 3 est supérieur à 2 et que l'instruction à l'intérieur de la clause guard else est ignorée et que True est imprimé.

Exemple 2:

func validate() {         
    guard 1>2 else {             
    print ("False")            //False 
    return         
    }         
    print ("True")      
} 
validate()

Dans l'exemple ci-dessus, nous voyons que 1 est inférieur à 2 et que l'instruction à l'intérieur de la clause guard else est exécutée et que False est imprimé suivi de return.

Example 3: gaurd let, unwrapping optionals through guard let

func getName(args myName: String?) {
     guard let name = myName, !name.isEmpty else {
     print ("Condition is false")          // Condition is false            return         
     }         
     print("Condition is met\(name)")     
} 
getName(args: "")

Dans l'exemple ci-dessus, nous utilisons un garde qui permet de déballer les options. Dans la fonction getName, nous avons défini une variable de type chaîne myName qui est facultative. Nous utilisons ensuite guard let pour vérifier si la variable myName est nulle ou non, si non assigner à name et vérifier à nouveau, name n'est pas vide. Si les deux conditions sont qualifiées, c'est-à-dire true, le bloc else est ignoré et affiche "Les conditions sont remplies avec nom".

Fondamentalement, nous vérifions ici deux choses séparées par une virgule, d’abord dépliante et facultative, et nous vérifions si cela satisfait ou non la condition.

Ici, nous ne transmettons rien à la fonction, c’est-à-dire une chaîne vide. La condition est false est print.

func getName(args myName: String?) {
     guard let name = myName, !name.isEmpty else {
     print ("Condition is false")          
     return         
     }        
     print("Condition is met \(name)") // Condition is met Hello    
} getName(args: "Hello")

Ici, nous passons "Hello" à la fonction et vous pouvez voir que le résultat est imprimé "La condition est remplie, Hello".

0
A H M