버그 잡이

Swift - Escaping Closure(탈출 클로저) 간단 이해 본문

Swift

Swift - Escaping Closure(탈출 클로저) 간단 이해

버그잡이 2020. 8. 13. 21:06

탈출 클로저(Escaping Closure)란?

 

함수의 인자로 전달된 클로저가 함수가 반환된 후 실행 되는 클로저을 의미합니다.

(말 그대로 전달인자로 받은 클로저가 함수 내부 scope 안에서 실행되는 것이 아니라 이를 탈출해서 다른 어딘가로 가는 것 입니다.)

 

다음과 같은 경우를 탈출한다고 볼 수 있습니다.

 

  1. 전달받은 클로저가 클로저 함수 외부로 다시 반환되거나
  2. 외부 글로벌 변수에 저장되는 경우

이 경우 @escaping을 붙여줘야 하고 그렇지 않으면 compile 에러를 냅니다.

이는 기존에 우리가 알고 있던 변수의 scope 개념을 무시합니다.

왜냐하면 함수에서 선언된 로컬 변수가 로컬 변수의 영역을 뛰어넘어 함수 밖에서도 유효하기 때문입니다.

 

 

왜 클로저를 탈출 시킬까요?

 

보통은 비동기 작업을 하기 위해서 클로저를 탈출시킵니다.

func getSumOf(array:[Int], handler: @escaping ((Int)->Void)) {
    var sum: Int = 0
    for value in array {
        sum += value
    }

    DispatchQueue.global().asyncAfter(deadline: .now() + 1.0){
        handler(sum)
    }
}

위 코드에는 handler라는 탈출 클로저가 있습니다.

이는 변수 sum을 받아 특정 작업을 수행하는 클로저입니다.

 

그런데 비동기로 할 경우 이 클로저는 함수 블록이 종료된 이후에 실행될 수 있습니다. 그렇다면 func 내부 지역 변수인 sum을 받을 수 있을까요?

일반적으로 지역 변수는 해당 메서드가 종료되면 같이 사라집니다.

 

하지만 탈출 클로저는 이 값을 계속 해서 가질 수 있습니다.

(탈출 클로저만의 메모리 공간을 만들어 주는 것이지요)

즉, 탈출 클로저를 활용하면 기존에 있던 함수 스코프 내부의 자원들을 활용해서 (scope가 종료되더라도) 비동기적인 작업을 가능하게 해줍니다.

 

그 결과 우리가 자주 볼 수 있는 아래와 같은 패턴의 코드가 탄생하는 것입니다.

func doSomething() {
    self.getSumOf(array: [16,756,442,6,23]) { (sum) in
        print(sum)
    }
}

 

네트워크 통신 간 사용하는 라이브러리 Alamofire도 위와 같은 구조입니다.

Alamofire.request(urlRequest).responseJSON { response in

}

response 값은 "func responseJSON()" 에 있는 지역 변수입니다.

네트워크 통신은 보통 비동기로 작업합니다. 그 결과 지역 변수인 response가 메모리에서 사라질 수 있죠. 탈출 클로저는 함수 반환 후에도 response 변수를 계속 잡고, 이후 함수 범위 밖에서도 이를 활용한 작업을 가능하게 해주는 것 입니다.

 

 

 

 

 

*참고 자료

https://oaksong.github.io/2018/03/02/escaping-closure/

https://hcn1519.github.io/articles/2017-09/swift_escaping_closure

반응형
Comments