TIL: @escaping / @autoclosure 키워드

Royce·2025년 3월 30일

Swift 문법

목록 보기
62/63

클로저의 실행 시점과 키워드 이해

클로저는 왜 @escaping이 필요한가

  • 기본적으로 함수가 종료되면 파라미터로 전달된 클로저도 함께 메모리에서 해제된다
  • 하지만 클로저가 함수 종료 이후에도 실행되어야 할 경우, 클로저는 함수의 실행 스코프를 "탈출"해야 한다
  • 이럴 때 사용하는 키워드가 @escaping이다
  • 대표적으로 비동기 처리(GCD), 클로저 저장 등에서 사용된다

함수 내부에서 즉시 실행되는 클로저

func executeNow(closure: () -> Void) {
    print("함수 시작")                // 함수 시작을 출력
    closure()                         // 전달받은 클로저 즉시 실행
    print("함수 종료")                // 함수 종료를 출력
}

executeNow {
    print("클로저 실행")               // 클로저 내용 출력
}
// 출력:
// 함수 시작
// 클로저 실행
// 함수 종료
  • 이 경우 클로저는 함수 내부에서 즉시 실행되는 구조이다
  • 함수의 실행 흐름을 벗어나지 않으므로 @escaping이 필요하지 않다
  • 함수가 종료되면 클로저도 메모리에서 함께 사라진다

클로저를 외부 변수에 저장하는 경우 @escaping 필요

var storedClosure: (() -> Void)? = nil  // 외부에서 클로저를 저장할 변수 정의

func storeClosure(closure: @escaping () -> Void) {
    storedClosure = closure               // 전달받은 클로저를 외부 변수에 저장
}

storeClosure {
    print("나중에 실행될 클로저")           // 저장만 하고 실행하지 않음
}

storedClosure?()                          // 외부에서 나중에 클로저 실행
// 출력: 나중에 실행될 클로저
  • 클로저가 함수 외부에 저장되어 함수 실행이 끝난 후에도 사용되므로 @escaping이 필요하다
  • @escaping이 없으면 컴파일 오류가 발생한다
  • 함수의 실행 흐름을 벗어나 클로저가 나중에 실행되는 경우에 해당한다

GCD 비동기 처리에서의 escaping

func fetchData(completion: @escaping (String) -> Void) {
    DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
        completion("데이터 수신 완료")     // 1초 뒤 비동기적으로 클로저 실행
    }
}

fetchData { result in
    print(result)                         // 비동기 작업 결과 출력
}
// 출력 (1초 후): 데이터 수신 완료
  • 클로저가 비동기적으로 실행되기 때문에 함수가 종료된 이후에 클로저가 실행된다
  • 따라서 @escaping이 필수로 필요하다

@autoclosure 키워드는 왜 사용하는가

  • @autoclosure표현식을 클로저로 자동 변환해주는 키워드이다
  • 클로저의 실행을 지연시킬 수 있으며, 호출 시점에 표현식이 평가된다
  • 주로 간단한 조건 판단이나 지연 평가가 필요한 곳에 사용된다
  • @autoclosure파라미터가 없는 클로저에만 사용 가능하다

@autoclosure 없이 직접 클로저 전달

func check(_ condition: () -> Bool) {
    if condition() {
        print("조건이 참이다")
    } else {
        print("조건이 거짓이다")
    }
}

check({ 1 < 2 })  // 출력: 조건이 참이다

@autoclosure 사용으로 표현식만 전달

func checkAuto(_ condition: @autoclosure () -> Bool) {
    if condition() {
        print("조건이 참이다")
    } else {
        print("조건이 거짓이다")
    }
}

checkAuto(1 < 2)  // 출력: 조건이 참이다
  • @autoclosure를 사용하면 호출 측에서는 클로저 문법 없이 표현식만 넘길 수 있다
  • 표현식은 클로저로 감싸져 있다가, 함수 내부에서 실제로 평가된다

@autoclosure@escaping 함께 사용

func delayedPrint(_ message: @autoclosure @escaping () -> String) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        print(message())  // 2초 뒤 메시지 출력
    }
}

delayedPrint("출력은 2초 뒤에")  // 출력: 출력은 2초 뒤에 (2초 후)
  • @autoclosure는 기본적으로 non-escaping이다
  • 비동기적으로 실행하기 위해서는 @escaping과 함께 사용해야 한다

요약 비교

상황@escaping 필요 여부설명
함수 내에서 즉시 실행필요 없음함수 스코프 내에서 클로저 실행됨
클로저를 외부 변수에 저장필요클로저가 함수 스코프를 벗어남
비동기 처리 (GCD 등)필요함수가 종료된 후 클로저가 실행됨
간단한 표현식 처리필요 없음@autoclosure로 자동 처리됨
@autoclosure + 비동기 처리필요평가를 지연하고 나중에 실행됨

요약

  • @escaping은 클로저가 함수 종료 이후에도 실행될 때 반드시 사용해야 한다
  • @autoclosure는 표현식을 자동으로 클로저로 변환해주는 키워드이다
  • @autoclosure는 주로 간단한 조건 검사나 지연 평가에서 사용된다
  • 두 키워드를 함께 사용하는 경우도 있으며, 이때는 @escaping이 필요하다
profile
iOS 개발자 지망생

0개의 댓글