사전개념: 클로저는 "이름 없는 함수" 이며 함수는 이름 있는 클로저다. 코드 블록을 변수처럼 다룰 수 있게 해준다.
일반 클로저
함수 내에서만 사용되고, 함수가 종료되면 사라진다.
@escaping 클로저
함수가 종료된 후에도 살아남아 나중에 실행될 수 있다
주로 비동기 작업에서 많이 사용된다
예를 들어
// 데이터를 다운로드하고 완료 후 실행할 작업을 받는 함수
func downloadData(completion: @escaping (String) -> Void) {
// @escaping: 이 클로저는 함수가 끝난 후에도 살아있을 수 있다
// DispatchQueue.global(): 백그라운드 큐를 가져옴
// .async: 비동기로 작업을 실행
DispatchQueue.global().async {
let downloadedData = "다운로드된 데이터"
// DispatchQueue.main: 메인 큐를 가져옴
// .async: 여기서도 비동기 실행
DispatchQueue.main.async {
// completion: 파라미터로 받은 클로저를 여기서 실행
// downloadedData를 인자로 넘기고
completion(downloadedData)
// 왜 메인 큐에서 실행되는지? UI 업데이트 때문인가?
//completion 클로저가 UI를 업데이트할 가능성이 있기 때문에 메인 큐에서 실행하여 잠재적인 UI 관련 문제를 예방
}
}
// 함수가 끝났지만 completion은 아직 실행 되지않았다.
// 실제 사용
downloadData { data in
// completion 클로저 정의. 데이터 다운로드 완료 시 호출됨
print("다운로드 완료:", data)
}
// 다운로드 시작 메시지 출력. 비동기 특성상 이 라인이 먼저 실행될 가능성 높음
print("다운로드 시작")
여기서 completion
클로저는 downloadData
함수가 끝난 후에도 살아남았다가 데이터 다운로드가 완료된 후에 실행되게된다.
Swift 컴파일러나 공동 작업자에게 "이 클로저는 함수가 끝난 후에도 사용될 거야"라고 직관적으로 알려주는 역할을 하며 메모리 관리에도 효율적이다