본문 바로가기

면접질문정리

@escaping closure에 대해서 설명하시오

escaping closure에 대해서 설명해주세요

키워드: 함수를 저장하고 비동기로 실행하기위해 사용, HTTP Request
스크립트: 클로저가 함수의 인자로 전달됐을떄, 함수의 실행이 종료된 후 실행되는 클로저 입니다. 즉, Non-Escaping 클로저는 이와 반대로 함수 실행이 종료되기 전에 실행되는 클로저입니다.

 
func runClosure(closure: () -> Void) {
 closure()
}

기본적으로 위 클로저가 실행되는 순서를 보면 runClosure함수의 closure인자로전달되고 함수안에서 closure가 실행됩니다.
그리고 runClosure함수가 값을 반환하고 종료하죠!

기본적으로 클로저가 함수가 종료되기전에 실행되는 특징이있습니다.

반면 아래의 @escaping클로져 같은경우에는

 
class ViewModel {
    var completionhandler: (() -> Void)? = nil
    
    func fetchData(completion: @escaping () -> Void) {
        completionhandler = completion
    }
}

클로저가 fetchData함수의 completion인자로전달됩니다.
그다음 클로저가 completion이 completionhandler변수에 저장됩니다.
그리고 fetchData함수가 값을 반환하고 종료됩니다.

클로저 completion은 아직 실행되지않은 상태입니다.

즉, completion은 함수의 실행이 종료되기전에 실행되지않기때문에 escaping 클로저, 다시말해 함수 밖에서 실행되는 클로저입니다.

escaping클로저가 사용되는 흔한 예로는 비동기로 실행되는 HTTP Request CompletionHandler가 있습니다.

 
func makeRequest(_ completion: @escaping (Result<(Data, URLResponse), Error>) -> Void) {
  URLSession.shared.dataTask(with: URL(string: "http://jusung.github.io/")!) { data, response, error in
    if let error = error {
      completion(.failure(error))
    } else if let data = data, let response = response {
      completion(.success((data, response)))
    }
  }
}

makeRequest함수에서 사용되는 completion클로저는 함수 실행중에 즉시 실행되지않고, URL요청이 끝난 후 비동기로 실행됩니다. 이 경우 completion의 타입에 @escaping을 붙여서 escaping클로저라는 것을 명시해줘야합니다.

즉, 보통 클로저가 다른 변수에 저장되어 나중에 실행되거나 비동기로 실행될때 escaping클로저가 사용됩니다.

꼬꼬무

1. 그럼 함수에 @escaping가 붙은 클로저에는 반드시 escaping클로저만 인자로 사용해야할까요 ?

키워드: @escaping은 둘다가능, Non은 non만취급
스크립트: 그렇지않습니다. @escaping이 붙어있어도 다음과 같이 non-escaping클로저를 인자로 넣을 수 있습니다. 하지만 반대로 escaping 클로저를 @escaping없이는 사용할 수 없습니다. 그럴시에는 컴파일에러가 발생합니다.

2. 아니그러면 굳이 @escaping을 붙여서 늘 사용하면 되는거아닌가? 복잡하게 non과 escaping을 나눌 필요가 있나요 ?

키워드: 컴파일러의 최적화(retain, release생략), 클로저가 함수밖에서 실행하는 것을 보장하기위해
스크립트: 이렇게 escaping, non-escaping을 나눠서 사용하는이유는 컴파일러의 퍼포먼스 최적화때문입니다. non-escaping클로저는 컴파일러가 클로저의 실행이 언제종료되는지알기때문에 , 때에 따라 클로저에서 사용한는 특정 객체에 대한 retain, release등의 처리를 생략해 객체의 라이프싸이클을 효율적으로 관리할 수 있게됩니다.반면 escaping클로저는 함수밖에서 실행되기에 클로저가 함수밖에서도 적절히 실행되는 것을 보장하기위해, 클로저에서 사용하는 객체에 대한 추가적인 참조싸이클(reference cycle)관리등을 해줘야합니다. 이부분이 컴파일러의 퍼포먼스와 최적화의 영향을 끼치기에 Swfit에서는 필요할때만 escaping클로저를 사용하도록 구분해두었습니다.

reference