스위프트 가드 키워드


197

Swift 2는 guard다양한 데이터를 준비 할 수 있도록 키워드를 도입했습니다 . 이 웹 사이트 에서 예제는 submitTapped 함수를 보여줍니다.

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

    print("All good")
}

조건을 guard사용하여 구식 방식으로 사용하는 것과 다른 것이 있는지 궁금합니다 if. 간단한 확인으로 얻을 수없는 이점이 있습니까?


또한 가드 대 if-let 질문
Honey

다음 링크를 참조하십시오 medium.com/@pvpriya7/swift-guard-18e59c50c624
Priyanka V

답변:


368

이 기사를 읽으 면서 Guard를 사용하면 큰 이점을 발견 했습니다

여기에서 guard의 사용을 예제와 비교할 수 있습니다 :

이것은 가드가없는 부분입니다.

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

    // Value requirements not met, do something
}
  1. 여기 모든 조건 내에서 원하는 코드를 넣습니다.

    당신은 즉시 이것에 대한 문제를 볼 수는 없지만, 당신이 진술을 실행하기 전에 충족시켜야 할 수많은 조건에 중첩되어 있다면 어떻게 혼란 스러울 수 있는지 상상할 수 있습니다.

이를 정리하는 방법은 먼저 각 점검을 수행하고, 충족되지 않으면 종료하는 것입니다. 이것은 어떤 조건이이 기능을 종료하게되는지 쉽게 이해할 수있게합니다.

그러나 이제 가드를 사용할 수 있으며 일부 문제를 해결할 수 있음을 알 수 있습니다.

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. 원하지 않는 상태가 아닌 원하는 상태를 확인합니다. 이것은 다시 assert와 유사합니다. 조건이 충족되지 않으면 guard의 else 문이 실행되어 기능에서 벗어날 수 있습니다.
  2. 조건이 통과되면 여기에서 선택적 변수가 보호문이 호출 된 범위 내에서 자동으로 랩핑 해제됩니다 (이 경우 fooGuard (_ :) 함수).
  3. 불량 사례를 조기에 확인하여 기능을보다 읽기 쉽고 유지 보수하기 쉽게 만듭니다.

이 같은 패턴은 선택 사항이 아닌 값에도 적용됩니다.

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
}

여전히 궁금한 점이 있으면 전체 기사 : Swift guard statement를 읽으십시오 .

마무리

마지막으로, 읽고 테스트 한 결과 가드를 사용하여 옵션을 풀면

그 래핑되지 않은 값은 나머지 코드 블록에서 사용할 수 있도록 유지됩니다.

.

guard let unwrappedName = userName else {
    return
}

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

래핑되지 않은 값은 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)")

3
안녕 @ 에릭 당신은 훌륭한 게시물을했다! 이해하기 쉽도록 도와 주셔서 감사합니다!
Jorge Casariego

1
NSError를 풀기 위해 guard를 사용하고 있습니다. 그러나 가드 범위 내에서 사용하려고하면 (예를 들어 일부 콜백에 오류를 전달하기 위해) "가드 조건에서 선언 된 변수는 본문에서 사용할 수 없습니다"라고 말합니다. 말이 되나요? 감사
GeRyCh

6
가드 문에서 @GeRyCh의 래핑을 해제하면 변수 가 가드 문 이후 가 아닌 가드 문 다음에 사용 가능 합니다. 이것에 익숙해지는 데 시간이 걸렸습니다.
DonnaLea

2
다음은 가드를 사용하여 옵션을 깨끗하게 풀기에 관한 훌륭한 기사 입니다. 잘 요약합니다.
Doches

let x = x where x > 0당신이 가진 의미합니까 결합 당신의 선택 바인딩에 다른 조건을? 나는 그것이 조금 다릅니다if let constantName = someOptional { statements }
Honey

36

달리 if, guard그 블록에 외부로부터 액세스 할 수있는 변수를 생성한다. Optionals를 많이 풀면 유용합니다 .


24

실제로 두 가지 큰 이점이 guard있습니다. 다른 사람들이 언급했듯이, 하나는 운명의 피라미드를 피하고 if let있습니다. 서로의 내부에 중첩 된 많은 성가신 말들이 점점 더 오른쪽으로 이동합니다.

다른 장점은 구현하려는 논리가 " if not let"보다 " if let { } else" 보다 많다는 것 입니다.

예를 들면 다음과 같습니다. 구현하고 싶다고 가정 해 봅시다 . 실행 간 축소를 제공하는 위치 와 그 accumulate사이의 교차점 입니다. 여기에 있습니다 :mapreduceguard

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

가드 없이 어떻게 작성 first하겠습니까? 하지만 여전히 사용 하면 선택 사항이 반환됩니까? 이 같은:

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

}

여분의 중첩은 성가 시지만 멀리 떨어져 if있는 else것이 논리적이지 않습니다 . 빈 경우에 대해 조기 종료를 한 다음 가능성이없는 것처럼 나머지 기능을 계속 사용하는 것이 훨씬 더 읽기 쉽습니다.


19

조건을 사용하여 충족 guard되면 guard블록 내에 선언 된 변수 가 나머지 코드 블록에 노출 되어 해당 범위로 들어갑니다. 이전에 언급했듯이 중첩 된 if let명령문 과 함께 유용 합니다.

guard 는 else 문에서 리턴 또는 스로우 를 요구합니다 .

Guard를 사용하여 JSON 구문 분석

아래는 if-let 대신 guard를 사용하여 JSON 객체를 구문 분석하는 방법의 예입니다. 다음은 놀이터 파일이 포함 된 블로그 항목에서 발췌 한 내용입니다.

Swift 2에서 Guard를 사용하여 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)

}

놀이터 다운로드 : 가드 놀이터

더 많은 정보:

다음은 The Swift Programming Language Guide 에서 발췌 한 내용입니다 .

가드 문의 조건이 충족되면 가드 문의 닫는 중괄호 후에 코드 실행이 계속됩니다. 조건의 일부로 선택적 바인딩을 사용하여 값이 지정된 변수 또는 상수는 guard 문이 나타나는 나머지 코드 블록에 대해 사용할 수 있습니다.

해당 조건이 충족되지 않으면 else 분기 내부의 코드가 실행됩니다. 해당 분기는 보호문을 표시하는 코드 블록을 종료하기 위해 제어를 전송해야합니다. 리턴, 중단 또는 계속과 같은 제어 전송 문으로이를 수행하거나 리턴되지 않는 함수 또는 메소드를 호출 할 수 있습니다. fatalError ()로.


7

한 가지 장점은 많은 중첩 된 if let진술을 제거한다는 것입니다 . "피라미드 오브 둠"섹션 15:30에 관한 WWDC "Swift의 새로운 기능"비디오를 참조하십시오.


6

경비원을 사용하는 경우

UITextField 요소가 몇 개 있거나 다른 유형의 사용자 입력이있는 뷰 컨트롤러가있는 경우 textField.text의 선택을 해제하여 내부의 텍스트 (있는 경우)를 가져와야한다는 것을 즉시 알 수 있습니다. isEmpty는 입력을하지 않으면 텍스트 필드가 단순히 nil을 반환합니다.

따라서 랩핑을 해제하고 결국 서버 엔드 포인트에 게시하는 함수에 전달하는 몇 가지가 있습니다. 우리는 서버 코드가 nil 값을 처리하거나 실수로 잘못된 값을 서버에 보내지 않기를 원하므로 먼저 입력 값을 가드로 랩 해제합니다.

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

서버 통신 기능은 선택 사항이 아닌 문자열 값을 매개 변수로 사용하므로 가드 언 래핑을 미리 알 수 있습니다. 언 래핑 (unwrapping)은 블록 내에서 사용할 값을 언 랩핑하는 경우 unwrapping에 익숙하기 때문에 약간 직관적이지 않습니다. 여기에 guard 문은 연관된 블록을 가지고 있지만 실제로는 else 블록입니다. 즉, unwrapping이 실패하면 수행하는 작업입니다. 값은 명령문 자체와 동일한 컨텍스트로 바로 래핑되지 않습니다.

// 우려의 분리

가드없이

가드를 사용하지 않으면 우리는 피라미드의 운명 과 비슷한 코드 더미를 갖게 됩니다. 양식에 새 필드를 추가하거나 코드를 읽기 쉽게 만들 수는 없습니다. 들여 쓰기는 따르기가 어려울 수 있으며, 특히 각 포크마다 다른 많은 문장이 있습니다.

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

예, let 문을 쉼표로 구분 된 단일 문으로 묶으면 이러한 모든 문을 결합 할 수도 있지만 어떤 문이 실패했는지 파악하여 사용자에게 메시지를 표시하는 기능을 잃게됩니다.

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


5

가드를 사용하면 우리의 강렬함이 분명합니다. 특정 조건이 만족되지 않으면 나머지 코드를 실행하고 싶지 않습니다. 여기서 우리는 체인을 확장 할 수 있습니다. 아래 코드를 살펴보십시오.

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

5

가드 성명서 그것은 다른 부부입니다

1) 중첩 된 if 문을 줄일 수 있습니다.
.2) 변수에 액세스 할 수있는 범위가 증가합니다.

if 문

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 
}

가드 진술

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 설명서에서 :

가드 진술

보호문은 하나 이상의 조건이 충족되지 않으면 프로그램 제어를 범위 밖으로 전달하는 데 사용됩니다.

시 낙스 :

guard condition else {
    statements
}

이점:

1. guard명령문 을 사용하여 요구 사항 세트의 유효성을 검증하는 유일한 중첩 조건문을 제거 할 수 있습니다.

2. 메소드 나 함수를 일찍 종료하기 위해 특별히 설계되었습니다.

아래에 보자면 사용하는 경우 코드 모양입니다.

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

guard를 사용하면 하나 이상의 조건이 충족되지 않으면 제어 범위 밖으로 제어를 전송할 수 있습니다.

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

참고:

1. 스위프트 2 : 가드로 조기 종료 2. Udacity 3. 가드 설명


그러나 if 문으로 후자를 할 수 있습니까? if condition { return }거친?
Oliver Dixon

2

if 문과 마찬가지로 guard는 표현식의 부울 값을 기반으로 명령문을 실행합니다. if 문과 달리 가드 문은 조건이 충족되지 않은 경우에만 실행됩니다. 가드를 Assert처럼 생각할 수 있지만 충돌하지 않고 정상적으로 종료 할 수 있습니다.

참조 : http://ericcerney.com/swift-guard-statement/


1

실제로 여러 조회 및 옵션을 사용하여 시퀀스의 흐름을 훨씬 간결하고 명확하게 만들고 중첩하는 경우 많이 줄입니다. Ifs 교체에 대한 Erica Sadun 게시물 참조하십시오 . .... 아래 예를들 수 있습니다.

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

그것이 붙어 있는지 확인하십시오.


1

간단히 말해서 실행 전에 필드를 검증하는 방법을 제공합니다. 가독성을 높이기 때문에 좋은 프로그래밍 스타일입니다. 다른 언어에서는 다음과 같이 보일 수 있습니다.

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

스위프트는 선택적 항목을 제공하기 때문에, 우리는이 전무의 여부를 확인 할 수 변수에 값을 할당합니다. 반대로 nilif let아닌지 확인 하고 실제 값을 보유 할 변수를 할당합니다. 여기가 시작 guard됩니다. 옵션을 사용하여 더 빨리 종료하는 더 간결한 방법을 제공합니다.


1

출처 : 스위프트 인 가드

그것을 명확하게 이해하는 예를 보자

예 1 :

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

위의 예에서 우리는 3이 2보다 크고 guard else 절 내부의 명령문이 생략되고 True가 인쇄되는 것을 볼 수 있습니다.

예 2 :

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

위의 예에서 우리는 1이 2보다 작고 guard else 절 내부의 명령문이 실행되고 False가 인쇄 된 다음 리턴된다는 것을 알 수 있습니다.

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

위의 예제에서 guard let을 사용하여 옵션을 풀 수 있습니다. getName 함수에서 선택적인 문자열 myName 유형의 변수를 정의했습니다. 그런 다음 guard let을 사용하여 변수 myName이 nil인지 여부를 확인하고 name에 지정하지 않은 경우 다시 확인하면 name이 비어 있지 않습니다. 두 조건이 모두 충족되면 (예 : true) else 블록을 건너 뛰고“조건이 이름과 일치합니다”를 인쇄합니다.

기본적으로 우리는 쉼표로 구분 된 두 가지 사항을 먼저 확인하고, 먼저 풀고 선택 사항이며 조건을 만족하는지 여부를 확인합니다.

여기서 우리는 함수에 아무것도 전달하지 않습니다. 즉 빈 문자열이므로 Condition is false is 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")

여기서는 "Hello"를 함수에 전달하고 출력이 "Condition is met Hello"로 출력되는 것을 볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.