🔥 defer

358자
5분

Swift에는 if문이나 while문처럼 코드의 실행 여부나 실행 횟수를 제어하는 제어문이 있습니다. 하지만 defer문은 이들과는 조금 다른 역할을 합니다. defer문은 코드의 실행 시점을 제어하는 역할을 하지요.

defer 블록 안에 작성된 코드는 현재 스코프(scope)의 끝에 도달했을 때 실행됩니다. 아래 예제 코드를 살펴볼까요?

var score = 1
if score < 10 {
    defer {
        print(score)
    }
    score += 5
}
// "6"이 출력됩니다.
swift

위 예제에서 defer 블록 안의 코드는 if문의 바디(body)를 빠져나가기 전에 실행됩니다. 먼저 if문 안의 코드가 실행되어 score가 5만큼 증가합니다. 그리고 if문의 스코프를 빠져나가기 전에 연기(deferred)된 코드가 실행되어 score를 출력하는 거죠.

defer 문의 실행 보장

defer 블록 안의 코드는 해당 스코프를 어떤 식으로 빠져나가든 항상 실행됩니다. 함수의 조기 종료(early return), for문의 중단(break), 에러 던지기(throwing an error) 등의 경우에도 말이죠. 이런 동작 방식 덕분에 defer문은 몇 가지 유용한 용도로 사용될 수 있답니다.

예를 들어, 메모리를 수동으로 할당하고 해제하는 작업, 로우 레벨 파일 디스크립터를 여닫는 작업, 데이터베이스 트랜잭션을 시작하고 끝내는 작업 등에서 defer문을 활용할 수 있습니다. 이런 작업들은 한 쌍으로 이뤄지는 경우가 많은데, defer문을 사용하면 코드 상에서 두 작업을 나란히 작성할 수 있기 때문이지요.

아래는 점수에 일시적으로 보너스를 주는 코드의 예시입니다. 코드 블록 안에서 100을 더하고 빼는 방식으로요.

var score = 3
if score < 100 {
    score += 100
    defer {
        score -= 100
    }
    // 보너스가 추가된 점수를 사용하는 다른 코드들이 여기에 들어갑니다.
    print(score)
}
// "103"이 출력됩니다.
swift

여러 개의 defer 블록

같은 스코프 안에 여러 개의 defer 블록을 작성할 수도 있습니다. 이 경우 가장 먼저 작성한 defer 블록이 가장 나중에 실행됩니다.

if score < 10 {
    defer {
        print(score)
    }
    defer {
        print("The score is:")
    }
    score += 5
}
// "The score is:"가 먼저 출력됩니다.
// 그 다음 "6"이 출력됩니다.
swift

defer 문과 에러 처리

프로그램이 런타임 에러나 크래시 등으로 인해 갑자기 멈추는 경우에는 defer 블록의 코드가 실행되지 않습니다. 하지만 에러가 던져진 후에는 defer 블록의 코드가 실행됩니다. defer문을 에러 처리와 함께 사용하는 방법에 대해서는 Specifying Cleanup Actions 부분을 참고해 주세요.

정리하면, defer문을 사용하면 현재 스코프가 끝나기 직전에 실행할 코드를 지정할 수 있답니다. 함수를 빠져나가는 방법에 상관없이 항상 실행되는 코드를 작성하는 데 유용하게 쓰일 수 있겠죠? 스코프를 나가기 전에 꼭 실행되어야 하는 작업이 있다면 defer문을 떠올려 보시기 바랍니다.