Swift'in güvenlik anahtar kelimesi


197

Swift 2 guard, çeşitli verilerin kullanıma hazır olarak yapılandırılmasını sağlamak için kullanılabilecek anahtar kelimeyi tanıttı . Bu web sitesinde gördüğüm bir örnek bir sendTapped işlevi göstermektedir:

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

    print("All good")
}

Kullanmanın guardeski moda yoldan, bir ifkoşul kullanarak yapmaktan farklı olup olmadığını merak ediyorum . Basit bir çekle elde edemeyeceğiniz faydalar sağlıyor mu?


Ayrıca bakınız nöbet vs if-let soru
Bal

Yanıtlar:


370

Okuma bu yazıyı kullanıyorum büyük faydalar fark Guard

Burada muhafız kullanımını bir örnekle karşılaştırabilirsiniz:

Bu, korumasız bölümdür:

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

    // Value requirements not met, do something
}
  1. Burada istediğiniz kodu tüm koşullara koyuyorsunuz

    Bu konuda hemen bir sorun görmeyebilirsiniz, ancak ifadelerinizi çalıştırmadan önce herkesin karşılanması gereken çok sayıda koşulla iç içe geçmişse ne kadar kafa karıştırıcı olabileceğini hayal edebilirsiniz.

Bunu temizlemenin yolu önce her bir kontrolünüzü yapmak ve karşılanmadığında çıkmaktır. Bu, bu fonksiyonun hangi koşullardan çıkacağını kolayca anlayabilmenizi sağlar.

Ama şimdi koruyucuyu kullanabiliriz ve bunun bazı sorunları çözmenin mümkün olduğunu görebiliriz:

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. İstediğiniz koşulu kontrol etmek, istemediğiniz durumu değil. Bu yine bir iddiaya benzer. Koşul karşılanmazsa, görevden ayrılan guard'ın başka ifadesi çalıştırılır.
  2. Koşul geçerse, buradaki isteğe bağlı değişken sizin için koruma ifadesinin çağrıldığı kapsamda otomatik olarak açılır - bu durumda fooGuard (_ :) işlevi.
  3. Kötü durumları erken kontrol edersiniz, işlevinizi daha okunabilir ve bakımı daha kolay hale getirir

Aynı model isteğe bağlı olmayan değerler için de geçerlidir:

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
}

Hâlâ sorularınız varsa makalenin tamamını okuyabilirsiniz: Swift guard ifadesi.

Paketleme

Ve son olarak, okuma ve test etme Herhangi bir seçeneği açmak için bekçi kullanırsanız,

bu kaydırılmamış değerler kod bloğunuzun geri kalanında kullanmanız için kalır

.

guard let unwrappedName = userName else {
    return
}

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

Burada, kaydırılmamış değer yalnızca if bloğunun içinde kullanılabilir

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)")

3
Hey @Eric mükemmel bir gönderi yaptın! Anlamanızı kolaylaştırdığınız için teşekkür ederiz!
Jorge Casariego

1
NSError paketini açmak için bekçi kullanıyorum. Ancak, koruma kapsamı içinde kullanmaya çalıştığımda (örneğin, bir hata geri çağrısına bir hata iletmek için), "Koruma koşulunda bildirilen değişken, gövdesinde kullanılamaz" diyor. Bir anlam ifade ediyor mu? Teşekkürler
GeRyCh

6
@GeRyCh bir nöbet deyiminde açma, bu değişkeni , nöbet deyiminden sonra kullanabilir , içinde değil. Buna alışmak için biraz zamanımı aldı.
DonnaLea

2
İşte opsiyonelleri temiz bir şekilde açmak için koruma kullanma hakkında bir başka mükemmel makale . Güzel özetliyor.
Doches

let x = x where x > 0birleştiğin demek miisteğe bağlı başka bir koşul ? Yani biraz farklıif let constantName = someOptional { statements }
Honey

36

Bunun aksine if, guardbloğunun dışından erişilebilen değişkeni oluşturur. Bir çok şeyi açmak yararlıdır Optional.


24

Gerçekten iki büyük faydası var guard. Birisi, diğerlerinin de bahsettiği gibi, kıyamet piramidinden kaçınmaktır - if letbirbirlerinin içine yerleştirilmiş çok sayıda can sıkıcı ifade, sağa ve ileriye doğru ilerler.

Diğer bir fayda ise genellikle uygulamak istediğiniz mantığın " if not let" den " if let { } else" daha fazla olmasıdır .

İşte bir örnek: uygulamak istediğinizi varsayalım accumulate- arasında bir çaprazlama mapve reducesize bir dizi koşu geri verir . İşte buradaguard :

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(+)  // []

Bunu nasıl yazardım olmadan bekçi, ama yine de kullanarakfirst isteğe bağlı olarak dönüyor mu? Bunun gibi bir şey:

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 []
        }
    }

}

Ekstra yuvalama sinir bozucu, ama aynı zamanda ifve bu elsekadar uzak olması mantıklı değil . Boş kasa için erken çıkışa sahip olmak çok daha okunabilir ve daha sonra sanki bu bir olasılık değildi.


19

Kullanılarak bir koşul karşılandığında guard, guardblok içinde bildirilen değişkenleri kod bloğunun geri kalanına maruz bırakır ve bunları kapsamına getirir. Daha önce de belirtildiği gibi, kesinlikle iç içe if letifadelerle kullanışlı olacaktır .

Muhafızların başka ifadesinde bir geri dönüş veya atış gerektirdiğini unutmayın .

JSON'u Guard ile Ayrıştırma

Aşağıda, bir JSON nesnesini if-let yerine guard kullanarak nasıl ayrıştırabileceğine bir örnek verilmiştir. Bu, burada bulabileceğiniz bir oyun alanı dosyası içeren bir blog girişinden bir alıntıdır:

Swift 2'de Guard JSON ayrıştırmak için nasıl kullanılır

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)

}

oyun indir: guard oyun alanı

Daha fazla bilgi:

İşte Swift Programlama Dili Kılavuzu'ndan bir alıntı :

Muhafız ifadesinin koşulu karşılanırsa, muhafız ifadesinin kapanış ayracı sonrasında kod yürütme devam eder. Koşulun bir parçası olarak isteğe bağlı bir bağlama kullanılarak değer atanan değişkenler veya sabitler, guard ifadesinin göründüğü kod bloğunun geri kalanı için kullanılabilir.

Bu koşul karşılanmazsa, diğer dalın içindeki kod yürütülür. Bu dal, koruma ifadesinin göründüğü kod bloğundan çıkmak için kontrolü aktarmalıdır. Bunu return, break veya devam gibi bir kontrol aktarma ifadesiyle yapabilir veya geri dönmeyen bir işlevi veya yöntemi çağırabilir fatalError () olarak.


7

Bunun bir faydası, birçok iç içe if letifadenin ortadan kaldırılmasıdır . 15:30 civarı "Kıyamet Piramidi" başlıklı WWDC "Swift'teki Yenilikler" videosunu izleyin.


6

Muhafızlar ne zaman kullanılır?

Birkaç UITextField öğesi veya başka bir kullanıcı girişi içeren bir görünüm denetleyiciniz varsa, içindeki metne (varsa!) Ulaşmak için isteğe bağlı olarak textField.text öğesinin paketini açmanız gerektiğini hemen fark edeceksiniz. isEmpty burada herhangi bir iyi yapmaz, herhangi bir giriş olmadan metin alanı sadece nil döndürür.

Böylece, paketini açıp sonunda bir sunucu uç noktasına gönderen bir işleve geçirdiğiniz bunlardan birkaçına sahip olursunuz. Sunucu kodunun sıfır değerlerle uğraşmasını veya yanlışlıkla geçersiz değerleri sunucuya göndermesini istemiyoruz, bu yüzden önce bu giriş değerlerini korumayla açacağız.

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) {
  ...
}

Sunucu iletişim fonksiyonumuzun isteğe bağlı olmayan Dize değerlerini parametre olarak aldığını ve böylece korumanın önceden açıldığını göreceksiniz. Açma işlemi biraz sezgisel değildir, çünkü bir blok içinde kullanmak için hangi değerleri açmaya izin verirse, açmayla alışmaya alışkınız. Burada guard ifadesinin ilişkili bir bloğu vardır, ancak aslında başka bir bloktur (yani, paketin açılması başarısız olursa yaptığınız şey), değerler ifadenin kendisiyle aynı içeriğe doğru kaydırılır.

// endişelerin ayrılması

Muhafızsız

Muhafız kullanmadan, bir kıyamet piramidine benzeyen büyük bir kod yığını ile sonuçlanırdık . Bu, formumuza yeni alanlar eklemek veya çok okunabilir kod oluşturmak için iyi ölçeklenmez. Girintiyi takip etmek zor olabilir, özellikle de her çataldaki diğer ifadelerle.

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")
    }
}

Evet, tüm ifadeleri virgülle ayrılmış tek bir ifadede bile birleştirebiliriz, ancak hangi ifadenin başarısız olduğunu anlamaya ve kullanıcıya bir mesaj sunma yeteneğini kaybederdik.

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


5

Koruyucu kullanarak niyetimiz açıktır. söz konusu koşul yerine getirilmezse kodun geri kalanını yürütmek istemiyoruz. burada zinciri de uzatabiliyoruz, lütfen aşağıdaki koda bir göz atın:

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

5

Muhafız açıklaması yapacak. birkaç farklı

1) ifade varsa iç içe azaltmama izin verir
2) değişkenimi erişilebilir olan kapsamımı arttırmak

if Deyimi

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 
}

Muhafız beyanı

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

}

3

Apple belgelerinden:

Muhafız Bildirimi

Koruma ifadesi, bir veya daha fazla koşul karşılanmadığı takdirde program kontrolünü bir kapsam dışına aktarmak için kullanılır.

Synatx:

guard condition else {
    statements
}

Avantajı:

1. İfadeyi kullanarak guard, tek amacı bir dizi gereksinimi doğrulamak olan derin yuvalanmış koşullardan kurtulabiliriz.

2. Bir yöntem veya fonksiyondan erken çıkmak için özel olarak tasarlanmıştır.

eğer let komutunu kullanırsanız aşağıdaki kod nasıl göründüğünü belirtir.

  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()

Bir ya da daha fazla koşulun gerçekleşmemesi durumunda korumayı kullanarak kontrolü kapsam dışına aktarabilirsiniz.

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()

Referans:

1. Swift 2: Muhafızla Erken Çık 2. Udacity 3. Muhafız Bildirimi


Ama ikincisini if ​​ifadeleriyle yapabilirsiniz? if condition { return }somurtkan?
Oliver Dixon

2

Bir if ifadesi gibi, guard da ifadenin Boole değerine dayalı ifadeler yürütür. Bir if ifadesinin aksine, guard ifadeleri yalnızca koşullar karşılanmadığında çalışır. Korumayı bir Assert gibi düşünebilirsiniz, ancak çökmek yerine, zarif bir şekilde çıkabilirsiniz.

bakınız: http://ericcerney.com/swift-guard-statement/


1

Gerçekten çok sayıda arama ve seçenek içeren bir dizinin akışını çok daha özlü ve net hale getirir ve iç içe geçme durumunda çok fazla azaltır. Ifs'ın yerini alan Erica Sadun yazısı . .... Taşınabilir, aşağıdaki örnek:

    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)}

Bakın, bu sopa.


1

Basitçe söylemek gerekirse, yürütmeden önce alanları doğrulamak için bir yol sağlar. Bu, okunabilirliği artırdığı için iyi bir programlama stilidir. Diğer dillerde, şöyle görünebilir:

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

Ancak Swift size opsiyonel özellikler sağladığından, sıfır olup olmadığını kontrol edemeyiz ve değerini bir değişkene atayamayız. Buna karşılık, nil olmadığınıif let kontrol eder ve gerçek değeri tutmak için bir değişken atar. İşte burada devreye giriyor. Opsiyonelleri erken kullanarak çıkmanın daha özlü bir yolunu sunar.guard


1

Kaynak: Guard in Swift

Açıkça anlamak için örneğe bakalım

Örnek 1:

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

Yukarıdaki örnekte, 3'ün 2'den büyük olduğunu ve diğer koruma yan tümcesi içindeki ifadenin atlandığını ve True yazdırıldığını görüyoruz.

Örnek 2:

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

Yukarıdaki örnekte, 1'in 2'den küçük olduğunu ve başka koruma yan tümcesi içindeki ifadenin yürütüldüğünü ve Yanlış yazdırıldıktan sonra geri döndüğünü görüyoruz.

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: "")

Yukarıdaki örnekte, opsiyonelleri açmak için guard let kullanıyoruz. GetName işlevinde, isteğe bağlı myName dizesi türünde bir değişken tanımladık. Daha sonra, myName değişkeninin nil olup olmadığını kontrol etmek için guard let'i kullanırız, isme atanmazsa ve tekrar kontrol ederseniz, ad boş değildir. Her iki koşul da koşullandırılmışsa (true) diğer blok atlanır ve “Koşullar adıyla karşılanır” yazdırılır.

Temelde, burada virgülle ayrılmış iki şeyi kontrol ediyoruz, ilk önce ambalajın açılması ve isteğe bağlı ve bunun koşulun karşılanıp karşılanmadığını kontrol ediyoruz.

Burada işleve hiçbir şey geçmiyoruz yani boş dize ve dolayısıyla Koşul yanlıştır yazdırma.

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")

Burada fonksiyona “Merhaba” u geçiyoruz ve çıktının “Koşullar Merhaba karşılandı” şeklinde yazdırıldığını görebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.