본문 바로가기

Swift

[Swift] Escaping Closure 탈출 하는 클로저!?

클로저(Closure)가 함수의 인자로 전달되고 함수 외부에서 실행될 때 함수를 탈출(escape)하는 클로저라고 합니다. 이 클로저는 함수가 반환된 후에 호출됩니다. 함수의 매개변수 타입 앞에 @escaping을 작성하여 해당 클로저가 함수를 탈출할 수 있음을 나타냅니다.

 

클로저가 함수를 탈출할 수 있는 방법은 함수 외부에 정의된 변수에 저장되는 것입니다. 예를 들어, 비동기 작업을 해야하는 많은 함수들은 completion handler 매개변수로 클로저를 받습니다. 해당 클로저는 함수의 작업이 완료될 때 까지 호출되지 않습니다. 즉, completion handler 는 함수의 작업이 완료된 후 호출되는 것을 보장받을 수 있습니다.

 

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}

 

someFunctionWithEscapingClosure 함수는 클로저를 매개변수로 받고 함수 외부에 선언된 배열에 해당 클로저를 저장합니다. @escaping 으로 이 함수의 매개변수를 표시하지 않으면 컴파일 오류가 발생합니다.

 

@escaping 으로 클로저를 표시하게 되면 클로저 내에서 self 를 꼭 표기하여 참조하여야 합니다. 반대로, 클로저에 @escaping을 표시하지 않고(non-escaping closure) 전달되게 된다면 함수 내부에서 해당 클로저가 실행되기 때문에 암시적으로 self 를 참조한다는 것을 알 수 있으므로 self 는 생략가능합니다.

 

func someFunctionWithNonescapingClosure(closure: () -> Void) {
    closure() // 함수 내부에서 클로저가 실행되므로 non-escaping
}

class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure { self.x = 100 } // self를 꼭 명시해야함
        someFunctionWithNonescapingClosure { x = 200 }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)
// Prints "200"

completionHandlers.first?()
print(instance.x)
// Prints "100"

정리

  • 클로저가 함수의 인자로 전달되고 함수 외부에서 실행되면 Escaping Closure 라고 합니다.
  • Escaping Closure를 이용하여 함수가 종결된 이 후 해당 클로저가 실행되는 것을 보장 받을 수 있습니다.
  • @escaping으로 표기된 클로저는 외부 값을 참조할 때 self 를 명시해야 합니다.