Ich habe über Optionals in Swift gelesen und Beispiele gesehen, bei denen if let
wird verwendet, um zu prüfen, ob ein Optional einen Wert enthält, und in diesem Fall - um etwas mit dem nicht umbrochenen Wert zu tun.
Ich habe jedoch gesehen, dass in Swift 2.0 das Schlüsselwort guard
am häufigsten verwendet wird. Ich frage mich, ob if let
wurde aus Swift 2.0 entfernt oder kann noch verwendet werden.
Soll ich meine Programme ändern, die if let
zu guard
?
if let
und guard let
dienen ähnlichen, aber unterschiedlichen Zwecken.
Der "else" -Fall von guard
muss den aktuellen Bereich verlassen. Im Allgemeinen bedeutet dies, dass return
aufgerufen oder das Programm abgebrochen werden muss. guard
wird verwendet, um eine vorzeitige Rückkehr zu ermöglichen, ohne dass der Rest der Funktion verschachtelt werden muss.
if let
verschachtelt seinen Gültigkeitsbereich und erfordert nichts Besonderes. Es kann return
oder nicht.
Im Allgemeinen, wenn die if-let
Block würde der Rest der Funktion sein, oder seine else
-Klausel würde einen return
oder Abbruch enthalten, dann sollten Sie stattdessen guard
verwenden. Dies bedeutet oft (zumindest nach meiner Erfahrung), dass guard
im Zweifelsfall normalerweise die bessere Antwort ist. Aber es gibt viele Situationen, in denen if let
ist immer noch angemessen.
Wann man if-let
Und wann guard
verwendet, ist oft eine Frage des Stils.
Angenommen, Sie haben func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
und ein optionales Array von Elementen (var optionalArray: [SomeType]?
), Und Sie müssen entweder 0
Zurückgeben, wenn das Array nil
ist (not- set) oder das count
, wenn das Array einen Wert hat (gesetzt ist).
Sie können es folgendermaßen implementieren: if-let
:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
if let array = optionalArray {
return array.count
}
return 0
}
oder wie folgt mit guard
:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
guard let array = optionalArray else {
return 0
}
return array.count
}
Die Beispiele sind funktional identisch.
Wo guard
wirklich glänzt, ist, wenn Sie eine Aufgabe wie das Überprüfen von Daten haben und möchten, dass die Funktion vorzeitig fehlschlägt, wenn etwas nicht stimmt.
Anstatt eine Reihe von if-let
- Elementen zu verschachteln, während Sie sich der Validierung nähern, befinden sich der "Erfolgspfad" und die nun erfolgreich gebundenen Optionen im Hauptbereich der Methode, da alle Fehlerpfade bereits zurückgegeben wurden .
Ich werde versuchen, die Nützlichkeit von Guard-Anweisungen mit einem (nicht optimierten) Code zu erklären.
Sie haben eine Benutzeroberfläche, in der Sie Textfelder für die Benutzerregistrierung mit Vorname, Nachname, E-Mail, Telefon und Passwort validieren.
Wenn ein textField keinen gültigen Text enthält, sollte dieses Feld als firstResponder angegeben werden.
hier ist der nicht optimierte Code:
//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()
}
}
Sie können oben sehen, dass auf alle Zeichenfolgen (firstNameString, lastNameString usw.) nur im Rahmen der if-Anweisung zugegriffen werden kann. Es schafft also diese "Pyramide des Schicksals" und hat viele Probleme damit, einschließlich der Lesbarkeit und der Leichtigkeit, Dinge zu bewegen (wenn die Reihenfolge der Felder geändert wird, müssen Sie den größten Teil dieses Codes neu schreiben).
Anhand der guard-Anweisung (im folgenden Code) können Sie erkennen, dass diese Zeichenfolgen außerhalb von {}
Verfügbar sind und verwendet werden, wenn alle Felder gültig sind.
// 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)
}
Wenn sich die Reihenfolge der Felder ändert, verschieben Sie einfach die entsprechenden Codezeilen nach oben oder unten, und schon können Sie loslegen.
Dies ist eine sehr einfache Erklärung und ein Anwendungsfall. Hoffe das hilft!
Grundlegender Unterschied
HINWEIS: Beide werden verwendet, um die optionale Variable zu entpacken.
Die klarste Erklärung, die ich gesehen habe, war im Github Swift Style Guide :
if
fügt eine Tiefenebene hinzu:
if n.isNumber {
// Use n here
} else {
return
}
guard
macht nicht:
guard n.isNumber else {
return
}
// Use n here
Eine Guard-Anweisung wird verwendet, um die Programmsteuerung aus einem Bereich zu verschieben, wenn eine oder mehrere Bedingungen nicht erfüllt sind.
Der Wert einer Bedingung in einer guard-Anweisung muss vom Typ Bool oder von einem mit Bool überbrückten Typ sein. Die Bedingung kann auch eine optionale verbindliche Erklärung sein
Eine Guard-Anweisung hat die folgende Form:
guard condition else {
//Generally return
}
- Auch beliebt als optionale Bindung
- Für den Zugriff auf das optionale Objekt verwenden wir falls erlaubt
if let roomCount = optionalValue {
print("roomCount available")
} else {
print("roomCount is nil")
}
Ich habe das gelernt von Swift mit Bob ..
Typisches anderes-Wenn
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")
}
}
Probleme mit Else-If
Guard Statement Ein Guard Block wird nur ausgeführt, wenn die Bedingung falsch ist, und verlässt die Funktion durch Return. Wenn die Bedingung erfüllt ist, ignoriert Swift den Schutzblock. Er bietet ein vorzeitiges Verlassen und weniger Klammern. +
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.
}
Optionals mit Else-If auspacken
Eine guard-Anweisung ist nicht nur nützlich, um einen typischen bedingten Block durch eine else-if-Anweisung zu ersetzen, sondern auch zum Auspacken von Optionen, indem die Anzahl der Klammern minimiert wird. Beginnen wir zum Vergleich damit, wie Sie mehrere Optionen mit else-if auspacken. Lassen Sie uns zunächst drei Optionen erstellen, die ausgepackt werden.
var publicName: String? = "Bob Lee"
var publicPhoto: String? = "Bob's Face"
var publicAge: Int? = nil
Der schlimmste Albtraum
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")
}
}
Der obige Code funktioniert zwar, verstößt aber gegen das Prinzip DRY=. Es ist grausam. Lassen Sie es uns zusammenfassen. +
Etwas besser Der folgende Code ist besser lesbar als oben. +
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
}
}
nwrap with Guard Die else-if-Anweisungen können durch guard ersetzt werden. +
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)
}
Mehrere Optionen mit Else-If auspacken Bisher haben Sie die Optionen einzeln ausgepackt. Swift ermöglicht das gleichzeitige Auspacken mehrerer Optionen. Wenn eine von ihnen nil enthält, wird der else-Block ausgeführt.
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")
}
}
Beachten Sie, dass Sie beim gleichzeitigen Auspacken mehrerer Optionen nicht erkennen können, welche Option nil enthält
Mehrere Optionen mit Guard auspacken Natürlich sollten wir Guard anstelle von else-if. + Verwenden
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
}