Swift 2.0 ‘Guard’ 문법

Swift 2.0 에서 소개된 여러가지 Syntax 중, guard에 대하여 소개한다.

원문 링크:  Swift Guard Statement

Apple의 WWDC 2015 , ‘Platform State of the Union’ 세션에서 새로 소개된 Swift 2.0의 新문법 guard에 대하여 처음 설명을 들었을때,  사용해야 하는 이유를 잘 알지 못했다. guard 문법은 무엇일까?

if 조건 문법과 마찬가지로, guard 문법은 Boolean 값을 리턴하는 표현식에 근거하여 분기한다. 그러나 if 와는 다르게 guard는 조건이 만족하지 않는 경우에만 실행된다. guardAssert와 비슷하게 생각해도 좋지만, 실행중인 프로그램의 충돌/종료를 피할 수 있다.


Diving In

guard 문법 vs. 기존의 방법을 비교해 보자

func fooManualCheck(x: Int?) {
    if x == nil || x <= 0 {
        // Value requirements not met, do something
        return
    }
    
    // Do stuff with x
    x!.description
}

위 예제[1]는 아주 기본적인 Objective-C 스타일의 방법으로 변수값의 존재 유무를 검사한다. 위 예제[1]은 정상적으로 동작하는데 문제는 없지만, 몇가지 문제점을 내포한다:

1.  원하는 변수 값(함수가 정상적으로 수행되기 위한) 대신에 원하지 않는 조건을 검사하게 된다. 이와같은 코드의 양이 많아지면, 혼동이 오게 된다. 정말로 원하는 것은 조건문이 통과하지 않는 것이다.

2. 조건문이 실패한 이후, optional 변수를 강제로 풀어줄(unwrap) 필요가 있다.

Swift는 위 문제점을 정리하고, 해결하기 위한 방법으로 Optional Binding이라는 기법을 제공하여 주었다:

func fooBinding(x: Int?) {
    if let x = x where x > 0 {
        // Do stuff with x
        x.description
    }
    
    // Value requirements not met, do something
}

위 예제[2]는 앞에서 제기한 두가지 문제점을 모두 해결해 준다. 하지만, 한가지 문제점이 추가적으로 발생하게 된다. 위 예제[2]에서 원하는 코드를 조건문 “속”에 넣을 수 있다. 직관적으로 문제점을 찾을 수 없을지도 모르지만, 만약에 수많은 조건문이 중첩된다면 코드를 분석하는데 얼마나 복잡해질지 생각해 보자.

그렇다면, 예제[2]의 문제를 해결하기 위한 방법은 무엇일까? 조건을 먼저 검사하고, 만약 어떤 조건도 만족하지 않는다면 조건문을 탈출하면 좋을 것이다. 이러한 방법은 어떠한 조건이 해당 함수를 탈출하는지에 대한 이해를 보다 쉽게 해준다.

해당 방법이 녹아 있는 guard 문법을 사용하면 아래와 같다:

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
}

guard 문법을 사용하면 위에 제기된 3가지의 이슈를 해결 가능하다:

1. 함수가 실행되기 원하는 조건을 체크할 수 있다. 만약 조건이 맞지 않는다면, 함수를 빠져나가는(예제에서) guardelse 문이 수행된다.

2. 만약 조건에 부합하는 경우, guard 문이 호출된 범위(Scope)안에서 optioinal 변수는 자동적으로 풀어진다(unwrap) – 예제에서 fooGuard(_:) 함수.  이러한 동작은 매우 중요하고 guard 문법을 보다 유용하게 해 준다.

3. 함수가 수행되지 않아야 하는 “나쁜” 조건을 사전에 검사할 수 있다. 이러한 코드 작성은 보다 가독성이 높으며 유지하기에도 쉬워진다.

guard 문법을 활용한 패턴은 optional 변수 케이스 이외에도 적용된다는 점에서 멋지다:

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
}

Wrapping Up

위 예제가 많은 도움이 되었기를 바라며, Swift 코드에 guard 문법을 빠른시일 내에 사용하여 함수/메소드가 보다 깔끔하고 가독성이 높으지게 하는것을 추천합니다.

Objective-C에서 Swift로 전환하는 것은 문법적인 측면 이외에도 큰 변화를 가져올지 모르지만, 코드의 구조적인 면을 바라보면 더 나은 측면을 발견할 수 있을 겁니다. 보다 능동적으로 Swift를 받아들여 당신의 코딩 스타일/패턴에 적용해 나가기를 기대해 봅니다.

개선사항 및 궁금한 점이 있다면, 알려주세요:)